Compare commits

..

1 Commits

Author SHA1 Message Date
Raphael Michel
f25097279c Refactor validation of cart contents, fix purchase of inactive subevent (Z#23217806) 2025-12-11 17:54:41 +01:00
26 changed files with 599 additions and 2371 deletions

View File

@@ -90,7 +90,6 @@ StaticMapping = namedtuple('StaticMapping', ('id', 'pretix_model', 'external_obj
class OutboundSyncProvider:
max_attempts = 5
list_field_joiner = "," # set to None to keep native lists in properties
def __init__(self, event):
self.event = event
@@ -282,8 +281,7 @@ class OutboundSyncProvider:
'Please update value mapping for field "{field_name}" - option "{val}" not assigned'
).format(field_name=key, val=val)])
if self.list_field_joiner:
val = self.list_field_joiner.join(val)
val = ",".join(val)
return val
def get_properties(self, inputs: dict, property_mappings: List[dict]):

View File

@@ -71,20 +71,15 @@ def assign_properties(
return out
def _add_to_list(out, field_name, current_value, new_item_input, list_sep):
def _add_to_list(out, field_name, current_value, new_item, list_sep):
new_item = str(new_item)
if list_sep is not None:
new_items = str(new_item_input).split(list_sep)
new_item = new_item.replace(list_sep, "")
current_value = current_value.split(list_sep) if current_value else []
else:
new_items = [str(new_item_input)]
if not isinstance(current_value, (list, tuple)):
current_value = [str(current_value)]
new_list = list(current_value)
for new_item in new_items:
if new_item not in current_value:
new_list.append(new_item)
if new_list != current_value:
elif not isinstance(current_value, (list, tuple)):
current_value = [str(current_value)]
if new_item not in current_value:
new_list = current_value + [new_item]
if list_sep is not None:
new_list = list_sep.join(new_list)
out[field_name] = new_list

View File

@@ -97,6 +97,10 @@ class CartError(Exception):
super().__init__(msg)
class CartPositionError(CartError):
pass
error_messages = {
'busy': gettext_lazy(
'We were not able to process your request completely as the '
@@ -106,6 +110,9 @@ error_messages = {
'unknown_position': gettext_lazy('Unknown cart position.'),
'subevent_required': pgettext_lazy('subevent', 'No date was specified.'),
'not_for_sale': gettext_lazy('You selected a product which is not available for sale.'),
'positions_removed': gettext_lazy(
'Some products have can no longer be purchased and have been removed from your cart for the following reason: %s'
),
'unavailable': gettext_lazy(
'Some of the products you selected are no longer available. '
'Please see below for details.'
@@ -258,6 +265,138 @@ def _get_voucher_availability(event, voucher_use_diff, now_dt, exclude_position_
return vouchers_ok, _voucher_depend_on_cart
def _check_position_constraints(
event: Event, item: Item, variation: ItemVariation, voucher: Voucher, subevent: SubEvent,
seat: Seat, sales_channel: SalesChannel, already_in_cart: bool, cart_is_expired: bool, real_now_dt: datetime,
item_requires_seat: bool, is_addon: bool, is_bundled: bool,
):
"""
Checks if a cart position with the given constraints can still be sold. This checks configuration and time-based
constraints of item, subevent, and voucher.
It does NOT
- check if quota/voucher/seat are still available
- check prices
- check memberships
- perform any checks that go beyond the single line (like item.max_per_order)
"""
time_machine_now_dt = time_machine_now(real_now_dt)
# Item or variation disabled
# Item disabled or unavailable by time
if not item.is_available(time_machine_now_dt) or (variation and not variation.is_available(time_machine_now_dt)):
raise CartPositionError(error_messages['unavailable'])
# Invalid media policy for online sale
if item.media_policy in (Item.MEDIA_POLICY_NEW, Item.MEDIA_POLICY_REUSE_OR_NEW):
mt = MEDIA_TYPES[item.media_type]
if not mt.medium_created_by_server:
raise CartPositionError(error_messages['media_usage_not_implemented'])
elif item.media_policy == Item.MEDIA_POLICY_REUSE:
raise CartPositionError(error_messages['media_usage_not_implemented'])
# Item removed from sales channel
if not item.all_sales_channels:
if sales_channel.identifier not in (s.identifier for s in item.limit_sales_channels.all()):
raise CartPositionError(error_messages['unavailable'])
# Variation removed from sales channel
if variation and not variation.all_sales_channels:
if sales_channel.identifier not in (s.identifier for s in variation.limit_sales_channels.all()):
raise CartPositionError(error_messages['unavailable'])
# Item disabled or unavailable by time in subevent
if subevent and item.pk in subevent.item_overrides and not subevent.item_overrides[item.pk].is_available(time_machine_now_dt):
raise CartPositionError(error_messages['not_for_sale'])
# Variation disabled or unavailable by time in subevent
if subevent and variation and variation.pk in subevent.var_overrides and \
not subevent.var_overrides[variation.pk].is_available(time_machine_now_dt):
raise CartPositionError(error_messages['not_for_sale'])
# Item requires a variation (should never happen)
if item.has_variations and not variation:
raise CartPositionError(error_messages['not_for_sale'])
# Variation belongs to wrong item (should never happen)
if variation and variation.item_id != item.pk:
raise CartPositionError(error_messages['not_for_sale'])
# Voucher does not apply to product
if voucher and not voucher.applies_to(item, variation):
raise CartPositionError(error_messages['voucher_invalid_item'])
# Voucher does not apply to seat
if voucher and voucher.seat and voucher.seat != seat:
raise CartPositionError(error_messages['voucher_invalid_seat'])
# Voucher does not apply to subevent
if voucher and voucher.subevent_id and voucher.subevent_id != subevent.pk:
raise CartPositionError(error_messages['voucher_invalid_subevent'])
# Voucher expired
if voucher and voucher.valid_until and voucher.valid_until < time_machine_now_dt:
raise CartPositionError(error_messages['voucher_expired'])
# Subevent has been disabled
if subevent and not subevent.active:
raise CartPositionError(error_messages['inactive_subevent'])
# Subevent sale not started
if subevent and subevent.presale_start and time_machine_now_dt < subevent.presale_start:
raise CartPositionError(error_messages['not_started'])
# Subevent sale has ended
if subevent and subevent.presale_has_ended:
raise CartPositionError(error_messages['ended'])
# Payment for subevent no longer possible
if subevent:
tlv = event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
if tlv:
term_last = make_aware(datetime.combine(
tlv.datetime(subevent).date(),
time(hour=23, minute=59, second=59)
), event.timezone)
if term_last < time_machine_now_dt:
raise CartPositionError(error_messages['payment_ended'])
# Seat required but no seat given
if item_requires_seat and not seat:
raise CartPositionError(error_messages['seat_invalid'])
# Seat given but no seat required
if seat and not item_requires_seat:
raise CartPositionError(error_messages['seat_forbidden'])
# Item requires to be add-on but is top-level position
if item.category and item.category.is_addon and not is_addon:
raise CartPositionError(error_messages['addon_only'])
# Item requires bundling but is top-level position
if item.require_bundling and not is_bundled:
raise CartPositionError(error_messages['bundled_only'])
# Seat for wrong product
if seat and seat.product != item:
raise CartPositionError(error_messages['seat_invalid'])
# Seat blocked
if seat and seat.blocked and sales_channel.identifier not in event.settings.seating_allow_blocked_seats_for_channel:
raise CartPositionError(error_messages['seat_invalid'])
# Item requires voucher but no voucher given
if item.require_voucher and voucher is None and not is_bundled:
raise CartPositionError(error_messages['voucher_required'])
# Item or variation is hidden without voucher but no voucher is given
if (
(item.hide_without_voucher or (variation and variation.hide_without_voucher)) and
(voucher is None or not voucher.show_hidden_items) and
not is_bundled
):
raise CartPositionError(error_messages['voucher_required'])
class CartManager:
AddOperation = namedtuple('AddOperation', ('count', 'item', 'variation', 'voucher', 'quotas',
'addon_to', 'subevent', 'bundled', 'seat', 'listed_price',
@@ -294,6 +433,7 @@ class CartManager:
self._widget_data = widget_data or {}
self._sales_channel = sales_channel
self.num_extended_positions = 0
self.price_change_for_extended = False
if reservation_time:
self._reservation_time = reservation_time
@@ -421,14 +561,14 @@ class CartManager:
if cartsize > limit:
raise CartError(error_messages['max_items'] % limit)
def _check_item_constraints(self, op, current_ops=[]):
def _check_item_constraints(self, op):
if isinstance(op, (self.AddOperation, self.ExtendOperation)):
if not (
(isinstance(op, self.AddOperation) and op.addon_to == 'FAKE') or
(isinstance(op, self.ExtendOperation) and op.position.is_bundled)
):
if op.item.require_voucher and op.voucher is None:
if getattr(op, 'voucher_ignored', False):
if getattr(op, 'voucher_ignored', False): # todo??
raise CartError(error_messages['voucher_redeemed'])
raise CartError(error_messages['voucher_required'])
@@ -440,88 +580,39 @@ class CartManager:
raise CartError(error_messages['voucher_redeemed'])
raise CartError(error_messages['voucher_required'])
if not op.item.is_available() or (op.variation and not op.variation.is_available()):
raise CartError(error_messages['unavailable'])
if op.item.media_policy in (Item.MEDIA_POLICY_NEW, Item.MEDIA_POLICY_REUSE_OR_NEW):
mt = MEDIA_TYPES[op.item.media_type]
if not mt.medium_created_by_server:
raise CartError(error_messages['media_usage_not_implemented'])
elif op.item.media_policy == Item.MEDIA_POLICY_REUSE:
raise CartError(error_messages['media_usage_not_implemented'])
if not op.item.all_sales_channels:
if self._sales_channel.identifier not in (s.identifier for s in op.item.limit_sales_channels.all()):
raise CartError(error_messages['unavailable'])
if op.variation and not op.variation.all_sales_channels:
if self._sales_channel.identifier not in (s.identifier for s in op.variation.limit_sales_channels.all()):
raise CartError(error_messages['unavailable'])
if op.subevent and op.item.pk in op.subevent.item_overrides and not op.subevent.item_overrides[op.item.pk].is_available():
raise CartError(error_messages['not_for_sale'])
if op.subevent and op.variation and op.variation.pk in op.subevent.var_overrides and \
not op.subevent.var_overrides[op.variation.pk].is_available():
raise CartError(error_messages['not_for_sale'])
if op.item.has_variations and not op.variation:
raise CartError(error_messages['not_for_sale'])
if op.variation and op.variation.item_id != op.item.pk:
raise CartError(error_messages['not_for_sale'])
if op.voucher and not op.voucher.applies_to(op.item, op.variation):
raise CartError(error_messages['voucher_invalid_item'])
if op.voucher and op.voucher.seat and op.voucher.seat != op.seat:
raise CartError(error_messages['voucher_invalid_seat'])
if op.voucher and op.voucher.subevent_id and op.voucher.subevent_id != op.subevent.pk:
raise CartError(error_messages['voucher_invalid_subevent'])
if op.subevent and not op.subevent.active:
raise CartError(error_messages['inactive_subevent'])
if op.subevent and op.subevent.presale_start and time_machine_now(self.real_now_dt) < op.subevent.presale_start:
raise CartError(error_messages['not_started'])
if op.subevent and op.subevent.presale_has_ended:
raise CartError(error_messages['ended'])
seated = self._is_seated(op.item, op.subevent)
if (
seated and (
not op.seat or (
op.seat.blocked and
self._sales_channel.identifier not in self.event.settings.seating_allow_blocked_seats_for_channel
)
)
):
raise CartError(error_messages['seat_invalid'])
elif op.seat and not seated:
raise CartError(error_messages['seat_forbidden'])
elif op.seat and op.seat.product != op.item:
raise CartError(error_messages['seat_invalid'])
elif op.seat and op.count > 1:
if op.seat and op.count > 1:
raise CartError('Invalid request: A seat can only be bought once.')
if op.subevent:
tlv = self.event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
if tlv:
term_last = make_aware(datetime.combine(
tlv.datetime(op.subevent).date(),
time(hour=23, minute=59, second=59)
), self.event.timezone)
if term_last < time_machine_now(self.real_now_dt):
raise CartError(error_messages['payment_ended'])
if isinstance(op, self.AddOperation):
is_addon = op.addon_to
is_bundled = op.addon_to == "FAKE"
else:
is_addon = op.position.addon_to
is_bundled = op.position.is_bundled
if isinstance(op, self.AddOperation):
if op.item.category and op.item.category.is_addon and not (op.addon_to and op.addon_to != 'FAKE'):
raise CartError(error_messages['addon_only'])
if op.item.require_bundling and not op.addon_to == 'FAKE':
raise CartError(error_messages['bundled_only'])
try:
_check_position_constraints(
event=self.event,
item=op.item,
variation=op.variation,
voucher=op.voucher,
subevent=op.subevent,
seat=op.seat,
sales_channel=self._sales_channel,
already_in_cart=isinstance(op, self.ExtendOperation),
cart_is_expired=isinstance(op, self.ExtendOperation),
real_now_dt=self.real_now_dt,
item_requires_seat=self._is_seated(op.item, op.subevent),
is_addon=is_addon,
is_bundled=is_bundled,
)
# Quota, seat, and voucher availability is checked for in perform_operations
# Price changes are checked for in extend_expired_positions
except CartPositionError as e:
if e.args[0] == error_messages['voucher_required'] and getattr(op, 'voucher_ignored', False):
# This is the case where someone clicks +1 on a voucher-only item with a fully redeemed voucher:
raise CartPositionError(error_messages['voucher_redeemed'])
raise
def _get_price(self, item: Item, variation: Optional[ItemVariation],
voucher: Optional[Voucher], custom_price: Optional[Decimal],
@@ -604,7 +695,11 @@ class CartManager:
quotas=quotas, subevent=cp.subevent, seat=cp.seat, listed_price=listed_price,
price_after_voucher=price_after_voucher,
)
self._check_item_constraints(op)
try:
self._check_item_constraints(op)
except CartPositionError as e:
self._operations.append(self.RemoveOperation(position=cp))
err = error_messages['positions_removed'] % str(e)
if cp.voucher:
self._voucher_use_diff[cp.voucher] += 2
@@ -797,7 +892,7 @@ class CartManager:
custom_price_input_is_net=False,
voucher_ignored=False,
)
self._check_item_constraints(bop, operations)
self._check_item_constraints(bop)
bundled.append(bop)
listed_price = get_listed_price(item, variation, subevent)
@@ -836,7 +931,7 @@ class CartManager:
custom_price_input_is_net=self.event.settings.display_net_prices,
voucher_ignored=voucher_ignored,
)
self._check_item_constraints(op, operations)
self._check_item_constraints(op)
operations.append(op)
self._quota_diff.update(quota_diff)
@@ -975,7 +1070,7 @@ class CartManager:
custom_price_input_is_net=self.event.settings.display_net_prices,
voucher_ignored=False,
)
self._check_item_constraints(op, operations)
self._check_item_constraints(op)
operations.append(op)
# Check constraints on the add-on combinations
@@ -1172,7 +1267,9 @@ class CartManager:
op.position.delete()
elif isinstance(op, (self.AddOperation, self.ExtendOperation)):
# Create a CartPosition for as much items as we can
if isinstance(op, self.ExtendOperation) and (op.position.pk in deleted_positions or not op.position.pk):
continue # Already deleted in other operation
# Create a CartPosition for as many items as we can
requested_count = quota_available_count = voucher_available_count = op.count
if op.seat:
@@ -1343,6 +1440,8 @@ class CartManager:
addons.delete()
op.position.delete()
elif available_count == 1:
if op.price_after_voucher != op.position.price_after_voucher:
self.price_change_for_extended = True
op.position.expires = self._expiry
op.position.max_extend = self._max_expiry_extend
op.position.listed_price = op.listed_price
@@ -1444,6 +1543,14 @@ class CartManager:
return diff
def _remove_parents_if_bundles_are_removed(self):
removed_positions = {op.position.pk for op in self._operations if isinstance(op, self.RemoveOperation)}
for op in self._operations:
if isinstance(op, self.RemoveOperation):
if op.position.is_bundled and op.position.addon_to_id not in removed_positions:
self._operations.append(self.RemoveOperation(position=op.position.addon_to))
removed_positions.add(op.position.addon_to)
def commit(self):
self._check_presale_dates()
self._check_max_cart_size()
@@ -1453,6 +1560,7 @@ class CartManager:
err = err or self._check_min_per_voucher()
self._extend_expiry_of_valid_existing_positions()
self._remove_parents_if_bundles_are_removed()
err = self._perform_operations() or err
self.recompute_final_prices_and_taxes()
@@ -1708,7 +1816,12 @@ def extend_cart_reservation(self, event: Event, cart_id: str=None, locale='en',
try:
cm = CartManager(event=event, cart_id=cart_id, sales_channel=sales_channel)
cm.commit()
return {"success": cm.num_extended_positions, "expiry": cm._expiry, "max_expiry_extend": cm._max_expiry_extend}
return {
"success": cm.num_extended_positions,
"expiry": cm._expiry,
"max_expiry_extend": cm._max_expiry_extend,
"price_changed": cm.price_change_for_extended,
}
except LockTimeoutException:
self.retry()
except (MaxRetriesExceededError, LockTimeoutException):

View File

@@ -81,7 +81,7 @@ from pretix.base.models.tax import TAXED_ZERO, TaxedPrice, TaxRule
from pretix.base.payment import GiftCardPayment, PaymentException
from pretix.base.reldate import RelativeDateWrapper
from pretix.base.secrets import assign_ticket_secret
from pretix.base.services import tickets
from pretix.base.services import cart, tickets
from pretix.base.services.invoices import (
generate_cancellation, generate_invoice, invoice_qualified,
invoice_transmission_separately, order_invoice_transmission_separately,
@@ -130,6 +130,9 @@ class OrderError(Exception):
error_messages = {
'positions_removed': gettext_lazy(
'Some products have can no longer be purchased and have been removed from your cart for the following reason: %s'
),
'unavailable': gettext_lazy(
'Some of the products you selected were no longer available. '
'Please see below for details.'
@@ -182,14 +185,6 @@ error_messages = {
'The voucher code used for one of the items in your cart is not valid for this item. We removed this item from your cart.'
),
'voucher_required': gettext_lazy('You need a valid voucher code to order one of the products.'),
'some_subevent_not_started': gettext_lazy(
'The booking period for one of the events in your cart has not yet started. The '
'affected positions have been removed from your cart.'
),
'some_subevent_ended': gettext_lazy(
'The booking period for one of the events in your cart has ended. The affected '
'positions have been removed from your cart.'
),
'seat_invalid': gettext_lazy('One of the seats in your order was invalid, we removed the position from your cart.'),
'seat_unavailable': gettext_lazy('One of the seats in your order has been taken in the meantime, we removed the position from your cart.'),
'country_blocked': gettext_lazy('One of the selected products is not available in the selected country.'),
@@ -744,13 +739,37 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
deleted_positions.add(cp.pk)
cp.delete()
sorted_positions = sorted(positions, key=lambda c: (-int(c.is_bundled), c.pk))
sorted_positions = list(sorted(positions, key=lambda c: (-int(c.is_bundled), c.pk)))
for cp in sorted_positions:
cp._cached_quotas = list(cp.quotas)
for cp in sorted_positions:
try:
cart._check_position_constraints(
event=event,
item=cp.item,
variation=cp.variation,
voucher=cp.voucher,
subevent=cp.subevent,
seat=cp.seat,
sales_channel=sales_channel,
already_in_cart=True,
cart_is_expired=cp.expires < now_dt,
real_now_dt=now_dt,
item_requires_seat=cp.requires_seat,
is_addon=bool(cp.addon_to_id),
is_bundled=bool(cp.addon_to_id) and cp.is_bundled,
)
# Quota, seat, and voucher availability is checked for below
# Prices are checked for below
# Memberships are checked in _create_order
except cart.CartPositionError as e:
err = error_messages['positions_removed'] % str(e)
delete(cp)
# Create locks
if any(cp.expires < now() + timedelta(seconds=LOCK_TRUST_WINDOW) for cp in sorted_positions):
if any(cp.expires < now() + timedelta(seconds=LOCK_TRUST_WINDOW) and cp.pk not in deleted_positions for cp in sorted_positions):
# No need to perform any locking if the cart positions still guarantee everything long enough.
full_lock_required = any(
getattr(o, 'seat', False) for o in sorted_positions
@@ -769,20 +788,17 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
# Check maximum order size
limit = min(int(event.settings.max_items_per_order), settings.PRETIX_MAX_ORDER_SIZE)
if sum(1 for cp in sorted_positions if not cp.addon_to) > limit:
if sum(1 for cp in sorted_positions if not cp.addon_to and cp.pk not in deleted_positions) > limit:
err = err or (error_messages['max_items'] % limit)
# Check availability
for i, cp in enumerate(sorted_positions):
if cp.pk in deleted_positions:
if cp.pk in deleted_positions or not cp.pk:
continue
if not cp.item.is_available() or (cp.variation and not cp.variation.is_available()):
err = err or error_messages['unavailable']
delete(cp)
continue
quotas = cp._cached_quotas
# Product per order limits
products_seen[cp.item] += 1
if cp.item.max_per_order and products_seen[cp.item] > cp.item.max_per_order:
err = error_messages['max_items_per_product'] % {
@@ -792,6 +808,7 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
delete(cp)
break
# Voucher availability
if cp.voucher:
v_usages[cp.voucher] += 1
if cp.voucher not in v_avail:
@@ -806,48 +823,14 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
delete(cp)
continue
if cp.subevent and cp.subevent.presale_start and time_machine_now_dt < cp.subevent.presale_start:
err = err or error_messages['some_subevent_not_started']
delete(cp)
break
if cp.subevent:
tlv = event.settings.get('payment_term_last', as_type=RelativeDateWrapper)
if tlv:
term_last = make_aware(datetime.combine(
tlv.datetime(cp.subevent).date(),
time(hour=23, minute=59, second=59)
), event.timezone)
if term_last < time_machine_now_dt:
err = err or error_messages['some_subevent_ended']
delete(cp)
break
if cp.subevent and cp.subevent.presale_has_ended:
err = err or error_messages['some_subevent_ended']
delete(cp)
break
if (cp.requires_seat and not cp.seat) or (cp.seat and not cp.requires_seat) or (cp.seat and cp.seat.product != cp.item) or cp.seat in seats_seen:
# Check duplicate seats in order
if cp.seat in seats_seen:
err = err or error_messages['seat_invalid']
delete(cp)
break
if cp.seat:
seats_seen.add(cp.seat)
if cp.item.require_voucher and cp.voucher is None and not cp.is_bundled:
delete(cp)
err = err or error_messages['voucher_required']
break
if (cp.item.hide_without_voucher or (cp.variation and cp.variation.hide_without_voucher)) and (
cp.voucher is None or not cp.voucher.show_hidden_items or not cp.voucher.applies_to(cp.item, cp.variation)
) and not cp.is_bundled:
delete(cp)
err = error_messages['voucher_required']
break
if cp.seat:
# Unlike quotas (which we blindly trust as long as the position is not expired), we check seats every
# time, since we absolutely can not overbook a seat.
if not cp.seat.is_available(ignore_cart=cp, ignore_voucher_id=cp.voucher_id, sales_channel=sales_channel.identifier):
@@ -855,34 +838,13 @@ def _check_positions(event: Event, now_dt: datetime, time_machine_now_dt: dateti
delete(cp)
continue
if cp.expires >= now_dt and not cp.voucher:
# Other checks are not necessary
continue
# Check useful quota configuration
if len(quotas) == 0:
err = err or error_messages['unavailable']
delete(cp)
continue
if cp.subevent and cp.item.pk in cp.subevent.item_overrides and not cp.subevent.item_overrides[cp.item.pk].is_available(time_machine_now_dt):
err = err or error_messages['unavailable']
delete(cp)
continue
if cp.subevent and cp.variation and cp.variation.pk in cp.subevent.var_overrides and \
not cp.subevent.var_overrides[cp.variation.pk].is_available(time_machine_now_dt):
err = err or error_messages['unavailable']
delete(cp)
continue
if cp.voucher:
if cp.voucher.valid_until and cp.voucher.valid_until < time_machine_now_dt:
err = err or error_messages['voucher_expired']
delete(cp)
continue
quota_ok = True
ignore_all_quotas = cp.expires >= now_dt or (
cp.voucher and (
cp.voucher.allow_ignore_quota or (cp.voucher.block_quota and cp.voucher.quota is None)

View File

@@ -207,7 +207,6 @@ class EventWizardBasicsForm(I18nModelForm):
'Sample Conference Center\nHeidelberg, Germany'
)
self.fields['slug'].widget.prefix = build_absolute_uri(self.organizer, 'presale:organizer.index')
self.fields['tax_rate']._required = True # Do not render as optional because it is conditionally required
if self.has_subevents:
del self.fields['presale_start']
del self.fields['presale_end']

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-27 13:57+0000\n"
"PO-Revision-Date: 2025-12-11 01:00+0000\n"
"PO-Revision-Date: 2025-12-09 07:09+0000\n"
"Last-Translator: Renne Rocha <renne@rocha.dev.br>\n"
"Language-Team: Portuguese (Brazil) <https://translate.pretix.eu/projects/"
"pretix/pretix/pt_BR/>\n"
@@ -816,22 +816,28 @@ msgstr ""
"confirme primeiro o endereço de email na sua conta."
#: pretix/base/datasync/datasync.py:263
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid ""
#| "Field \"{field_name}\" is not valid for {available_inputs}. Please check "
#| "your {provider_name} settings."
msgid ""
"Field \"{field_name}\" does not exist. Please check your {provider_name} "
"settings."
msgstr ""
"O campo \"{field_name}\" não existe. Por favor, verifique as configurações "
"de {provider_name}."
"O campo \"{field_name}\" não é válido para {available_inputs}. Verifique as "
"configurações de {provider_name}."
#: pretix/base/datasync/datasync.py:270
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid ""
#| "Field \"{field_name}\" is not valid for {available_inputs}. Please check "
#| "your {provider_name} settings."
msgid ""
"Field \"{field_name}\" requires {required_input}, but only got "
"{available_inputs}. Please check your {provider_name} settings."
msgstr ""
"Campo \"{field_name}\" exige {required_input}, mas apenas {available_inputs} "
"foram fornecidas. Por favor, verifique as configurações de {provider_name}."
"O campo \"{field_name}\" não é válido para {available_inputs}. Verifique as "
"configurações de {provider_name}."
#: pretix/base/datasync/datasync.py:281
#, python-brace-format
@@ -2131,7 +2137,7 @@ msgstr "Comprar este produto requer aprovação"
#: pretix/base/exporters/items.py:85 pretix/base/models/items.py:627
msgid "Only sell this product as part of a bundle"
msgstr "Venda este produto apenas como parte de um pacote"
msgstr "Disponível apenas como parte de um pacote"
#: pretix/base/exporters/items.py:86 pretix/base/models/items.py:634
msgid "Allow product to be canceled or changed"
@@ -2833,7 +2839,7 @@ msgstr "Código de Status"
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html:25
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/transaction_list.html:13
msgid "Amount"
msgstr "Quantidade"
msgstr "Valor"
#: pretix/base/exporters/orderlist.py:1098
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:102
@@ -3392,8 +3398,6 @@ msgid ""
"If you enter an invoice address, you also need to select an invoice "
"transmission method."
msgstr ""
"Se você informar um endereço para a fatura, você também deverá selecionar um "
"método para transmissão da fatura."
#: pretix/base/forms/questions.py:1385
msgid ""
@@ -3408,8 +3412,6 @@ msgid ""
"The selected type of invoice transmission requires a field that is currently "
"not available, please reach out to the organizer."
msgstr ""
"O tipo de transmissão de fatura selecionado exige um campo que não está "
"disponível atualmente. Por favor, entre em contato com a organização."
#: pretix/base/forms/questions.py:1398
msgid "This field is required for the selected type of invoice transmission."
@@ -13203,13 +13205,13 @@ msgid "Contact:"
msgstr "Contato:"
#: pretix/base/templates/pretixbase/email/order_details.html:54
#, python-format
#, fuzzy, python-format
#| msgid ""
#| "You are receiving this email because you placed an order for {event}."
msgid ""
"You are receiving this email because you placed an order for "
"<strong>%(event)s</strong>."
msgstr ""
"Você está recebendo este email por ter realizado um pedido para <strong>%"
"(event)s</strong>."
msgstr "Você está recebendo este email porque fez um pedido para {event}."
#: pretix/base/templates/pretixbase/email/order_details.html:93
#: pretix/control/templates/pretixcontrol/organizers/customer.html:23
@@ -17343,9 +17345,13 @@ msgid "Your account has been disabled."
msgstr "Sua conta foi desativada."
#: pretix/control/logdisplay.py:672
#, python-brace-format
#, fuzzy, python-brace-format
#| msgid ""
#| "The email address has been changed from \"{old_email}\" to \"{new_email}"
#| "\"."
msgid "Your email address has been changed from {old_email} to {email}."
msgstr "Seu endereço de email foi modificado de {old_email} para {email}."
msgstr ""
"O endereço de e-mail foi alterado de \"{old_email}\" para \"{new_email}\"."
#: pretix/control/logdisplay.py:673
#, python-brace-format
@@ -33726,11 +33732,12 @@ msgstr "Selecione como deseja pagar o saldo restante:"
#: pretix/presale/templates/pretixpresale/event/checkout_payment.html:82
#: pretix/presale/templates/pretixpresale/event/order_pay_change.html:45
#, python-format
#, fuzzy, python-format
#| msgid "%(num)s available"
msgid "(%(count)s available)"
msgid_plural "(%(count)s available)"
msgstr[0] "(%(count)s disponível)"
msgstr[1] "(%(count)s disponíveis)"
msgstr[0] "%(num)s disponíveis"
msgstr[1] "%(num)s disponíveis"
#: pretix/presale/templates/pretixpresale/event/checkout_payment.html:101
msgid "This sales channel does not provide support for test mode."
@@ -34509,11 +34516,13 @@ msgstr "Mostrar imagem em tamanho real de %(item)s"
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:131
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:288
#, python-format
#, fuzzy, python-format
#| msgid "%(count)s event"
#| msgid_plural "%(count)s events"
msgid "%(amount)s× in your cart"
msgid_plural "%(amount)s× in your cart"
msgstr[0] "%(amount)s× no seu carrinho"
msgstr[1] "%(amount)s× no seu carrinho"
msgstr[0] "%(count)s evento"
msgstr[1] "%(count)s events"
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:209
#: pretix/presale/templates/pretixpresale/event/fragment_product_list.html:374
@@ -35599,7 +35608,7 @@ msgid ""
"This is a self-hosted installation of <a %(a_attr)s>pretix, your free and "
"open source ticket sales software</a>."
msgstr ""
"Esta é uma instalação auto-hospedada do <a %(a_attr)s>pretix, seu aplicativo "
"Está é uma instalação self-hosted do <a %(a_attr)s>pretix, seu aplicativo "
"livre e de código aberto para venda de ingressos.</a>."
#: pretix/presale/templates/pretixpresale/index.html:15
@@ -35695,9 +35704,10 @@ msgid "Issued on %(date)s"
msgstr "Leitura negada: %(date)s"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:38
#, python-format
#, fuzzy, python-format
#| msgid "Expired since"
msgid "Expired since %(date)s"
msgstr "Expirado desde %(date)s"
msgstr "Expirado desde"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:46
#, python-format
@@ -35705,8 +35715,10 @@ msgid "Valid until %(date)s"
msgstr "Válido até %(date)s"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:66
#, fuzzy
#| msgid "Remaining balance"
msgid "Remaining value:"
msgstr "Valor restante:"
msgstr "Saldo restante"
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:76
#, fuzzy

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-27 13:57+0000\n"
"PO-Revision-Date: 2025-12-11 01:00+0000\n"
"PO-Revision-Date: 2025-12-02 16:47+0000\n"
"Last-Translator: Ana Rute Pacheco Vivas <rute.vivas@om.org>\n"
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
"pretix/pretix/pt_PT/>\n"
@@ -3522,7 +3522,8 @@ msgstr "Participante individual"
#: pretix/base/invoicing/email.py:50
msgid "Email invoice directly to accounting department"
msgstr "Envia a fatura diretamente por e-mail para o departamento financeiro"
msgstr ""
"Envie a fatura diretamente por e-mail para o departamento de contabilidade"
#: pretix/base/invoicing/email.py:51
msgid ""
@@ -6701,8 +6702,10 @@ msgstr ""
"tua fatura, caso assim o desejes."
#: pretix/base/models/orders.py:3534
#, fuzzy
#| msgid "Transaction time"
msgid "Transmission type"
msgstr "Modo de comunicação"
msgstr "Hora de transação"
#: pretix/base/models/orders.py:3632
#: pretix/plugins/badges/templates/pretixplugins/badges/control_order_position_buttons.html:9
@@ -20183,8 +20186,8 @@ msgid ""
"email address is owned by you. Please enter the verification code below:"
msgstr ""
"Enviamos um e-mail para %(recp)s com um código de confirmação para verificar "
"se este endereço de e-mail te pertence. Por favor, indica o código de "
"verificação abaixo:"
"se este endereço de e-mail é da sua propriedade. Por favor, insira o código "
"de verificação abaixo:"
#: pretix/control/templates/pretixcontrol/email_setup_simple.html:63
msgid "Verification code"
@@ -27451,9 +27454,6 @@ msgid ""
"We will send a confirmation code to your new email address, which you need "
"to enter in the next step to confirm the email address is correct."
msgstr ""
"Enviaremos um código de confirmação para o teu novo endereço de e-mail, que "
"precisas de inserir na próxima etapa para confirmar que o endereço de e-mail "
"está correto."
#: pretix/control/templates/pretixcontrol/user/change_password.html:4
#: pretix/control/templates/pretixcontrol/user/change_password.html:8
@@ -27567,9 +27567,6 @@ msgid ""
"confirm your email address using a confirmation code we will send to your "
"email address."
msgstr ""
"O teu endereço de e-mail ainda não foi confirmado. Para proteger a tua "
"conta, confirma o teu endereço de e-mail usando um código de confirmação que "
"te enviaremos."
#: pretix/control/templates/pretixcontrol/user/settings.html:18
#, fuzzy
@@ -28881,7 +28878,7 @@ msgstr ""
#: pretix/control/views/mailsetup.py:216
msgid "The verification code was incorrect, please try again."
msgstr "O código de verificação estava incorreto, tenta novamente."
msgstr "O código de verificação estava incorreto, tente novamente."
#: pretix/control/views/mailsetup.py:221
msgid "Sender address verification"
@@ -29940,8 +29937,6 @@ msgid ""
"Please enter the confirmation code we sent to your email address "
"<strong>{email}</strong>."
msgstr ""
"Indica o código de confirmação que enviámos para o teu endereço de e-mail "
"<strong>{email}</strong>."
#: pretix/control/views/user.py:947
#, fuzzy
@@ -34944,7 +34939,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/event/checkout_questions.html:9
msgid "Before we continue, we need you to answer some questions."
msgstr "Antes de continuares, precisamos que respondas a algumas perguntas."
msgstr "Antes de continuarmos, precisamos que respondas a algumas perguntas."
#: pretix/presale/templates/pretixpresale/event/checkout_questions.html:49
msgid "Auto-fill with address"
@@ -35379,8 +35374,10 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:514
#: pretix/presale/templates/pretixpresale/fragment_modals.html:48
#, fuzzy
#| msgid "Event description"
msgid "Renew reservation"
msgstr "Renovar a reserva"
msgstr "Descrição do Evento"
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:526
#, fuzzy
@@ -35965,8 +35962,8 @@ msgid ""
"Please note that we still await approval by the event organizer before you "
"can pay and complete this order."
msgstr ""
"Por favor, nota que ainda estamos à espera da aprovação do organizador do "
"evento antes de poderes pagar e concluir esta encomenda."
"Por favor, note que a aprovação ainda aguardam pelo organizador do evento "
"antes que pode pagar e concluir este pedido."
#: pretix/presale/templates/pretixpresale/event/order.html:43
msgid "Please note that we still await your payment to complete the process."
@@ -35975,14 +35972,19 @@ msgstr ""
"processo."
#: pretix/presale/templates/pretixpresale/event/order.html:55
#, fuzzy
#| msgid ""
#| "Please bookmark or save the link to this exact page if you want to access "
#| "your order later. We also sent you an email containing the link to the "
#| "address you specified."
msgid ""
"Please bookmark or save the link to this exact page if you want to access "
"your order later. We also sent you an email to the address you specified "
"containing the link to this page."
msgstr ""
"Por favor, guarda o link desta página, se quiseres aceder à tua encomenda "
"mais tarde. Também enviámos um e-mail para o endereço que indicaste com o "
"link para esta página."
"Por favor, guarda o link para esta página, caso queiras aceder ao teu pedido "
"mais tarde. Também iremos enviar-te um email com o link para o endereço que "
"indicaste."
#: pretix/presale/templates/pretixpresale/event/order.html:59
#, fuzzy

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-20 10:37+0000\n"
"PO-Revision-Date: 2025-12-10 15:49+0000\n"
"PO-Revision-Date: 2025-11-11 21:00+0000\n"
"Last-Translator: Ana Rute Pacheco Vivas <rute.vivas@om.org>\n"
"Language-Team: Portuguese (Portugal) <https://translate.pretix.eu/projects/"
"pretix/pretix-js/pt_PT/>\n"
@@ -798,7 +798,7 @@ msgstr ""
#: pretix/static/pretixpresale/js/ui/cart.js:90
msgid "Renew reservation"
msgstr "Renovar a reserva"
msgstr ""
#: pretix/static/pretixpresale/js/ui/main.js:194
msgid "The organizer keeps %(currency)s %(amount)s"

View File

@@ -8,20 +8,18 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-27 13:57+0000\n"
"PO-Revision-Date: 2025-12-09 22:00+0000\n"
"Last-Translator: Lachlan Struthers <lachlan.struthers@om.org>\n"
"Language-Team: Albanian <https://translate.pretix.eu/projects/pretix/pretix/"
"sq/>\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: sq\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.14.3\n"
#: pretix/_base_settings.py:87
msgid "English"
msgstr "Anglisht"
msgstr ""
#: pretix/_base_settings.py:88
msgid "German"
@@ -452,7 +450,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/event/mail.html:114
#: pretix/control/views/orders.py:1569
msgid "Order canceled"
msgstr "Porositja ësthë anuluar"
msgstr ""
#: pretix/api/webhooks.py:278 pretix/base/notifications.py:257
msgid "Order reactivated"
@@ -1409,7 +1407,7 @@ msgstr ""
#: pretix/plugins/checkinlists/exporters.py:827
#: pretix/plugins/checkinlists/exporters.py:828
msgid "Yes"
msgstr "Po"
msgstr ""
#: pretix/base/exporters/customers.py:100
#: pretix/base/exporters/customers.py:101 pretix/base/exporters/events.py:83
@@ -1433,7 +1431,7 @@ msgstr "Po"
#: pretix/plugins/checkinlists/exporters.py:827
#: pretix/plugins/checkinlists/exporters.py:828
msgid "No"
msgstr "Jo"
msgstr ""
#: pretix/base/exporters/dekodi.py:42 pretix/base/exporters/invoices.py:66
msgctxt "export_category"
@@ -2447,7 +2445,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:12
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:91
msgid "Product"
msgstr "Produkti"
msgstr ""
#: pretix/base/exporters/orderlist.py:619 pretix/base/models/vouchers.py:315
#: pretix/control/templates/pretixcontrol/vouchers/bulk.html:5
@@ -2785,7 +2783,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/event/cancel.html:20
#: pretix/control/views/item.py:971
msgid "Paid orders"
msgstr "Porositje të paguara"
msgstr ""
#: pretix/base/exporters/orderlist.py:1155 pretix/control/views/item.py:976
msgid "Pending orders"
@@ -3881,7 +3879,7 @@ msgstr ""
#: pretix/base/modelimport_vouchers.py:205 pretix/base/models/items.py:1256
#: pretix/base/models/vouchers.py:266 pretix/base/models/waitinglist.py:99
msgid "Product variation"
msgstr "Varianti i produktit"
msgstr ""
#: pretix/base/modelimport_orders.py:161
msgid "The variation can be specified by its internal ID or full name."
@@ -4280,19 +4278,19 @@ msgstr ""
#: pretix/base/models/checkin.py:336
msgid "Entry"
msgstr "Hyrje"
msgstr ""
#: pretix/base/models/checkin.py:337
msgid "Exit"
msgstr "Dalje"
msgstr ""
#: pretix/base/models/checkin.py:356
msgid "Unknown ticket"
msgstr "Biletë e panjohur"
msgstr ""
#: pretix/base/models/checkin.py:357
msgid "Ticket not paid"
msgstr "Bileta nuk është paguar"
msgstr ""
#: pretix/base/models/checkin.py:358
msgid "Forbidden by custom rule"
@@ -4300,23 +4298,23 @@ msgstr ""
#: pretix/base/models/checkin.py:359
msgid "Ticket code revoked/changed"
msgstr "Kodi i biletës është anuluar/ndryshuar"
msgstr ""
#: pretix/base/models/checkin.py:360
msgid "Information required"
msgstr "Informacion i domosdoshëm"
msgstr ""
#: pretix/base/models/checkin.py:361
msgid "Ticket already used"
msgstr "Bileta tashmë është përdorur"
msgstr ""
#: pretix/base/models/checkin.py:362
msgid "Ticket type not allowed here"
msgstr "Ky lloj bilete nuk lejohet këtu"
msgstr ""
#: pretix/base/models/checkin.py:363
msgid "Ticket code is ambiguous on list"
msgstr "Kodi i biletës është e paqartë në listë"
msgstr ""
#: pretix/base/models/checkin.py:364
msgid "Server error"
@@ -4324,15 +4322,15 @@ msgstr ""
#: pretix/base/models/checkin.py:365
msgid "Ticket blocked"
msgstr "Bileta u bllokua"
msgstr ""
#: pretix/base/models/checkin.py:366
msgid "Order not approved"
msgstr "Porositje nuk është aprovuar"
msgstr ""
#: pretix/base/models/checkin.py:367
msgid "Ticket not valid at this time"
msgstr "Bileta nuk është e vlefshme për momentin"
msgstr ""
#: pretix/base/models/checkin.py:368
msgid "Check-in annulled"
@@ -4462,7 +4460,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/organizers/gates.html:16
#: pretix/plugins/checkinlists/exporters.py:769
msgid "Gate"
msgstr "Porta"
msgstr ""
#: pretix/base/models/devices.py:131
#: pretix/control/templates/pretixcontrol/organizers/devices.html:83
@@ -5930,7 +5928,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/organizers/customer_membership.html:34
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html:44
msgid "Canceled"
msgstr "e anuluar"
msgstr ""
#: pretix/base/models/memberships.py:134
#: pretix/control/templates/pretixcontrol/organizers/customer.html:117
@@ -6673,7 +6671,7 @@ msgstr ""
#: pretix/base/models/vouchers.py:204 pretix/control/views/vouchers.py:120
msgid "Redeemed"
msgstr "e përdorur"
msgstr ""
#: pretix/base/models/vouchers.py:209
msgid ""
@@ -7706,15 +7704,15 @@ msgstr ""
#: pretix/base/reldate.py:38
msgid "Event start"
msgstr "Fillimi i eventit"
msgstr ""
#: pretix/base/reldate.py:39
msgid "Event end"
msgstr "Mbarimi i eventit"
msgstr ""
#: pretix/base/reldate.py:40
msgid "Event admission"
msgstr "Hyrja në event"
msgstr ""
#: pretix/base/reldate.py:41
msgid "Presale start"
@@ -12891,7 +12889,7 @@ msgstr ""
#: pretix/plugins/reports/exporters.py:391
#: pretix/presale/templates/pretixpresale/event/fragment_order_status.html:7
msgid "Approval pending"
msgstr "Duke pritur aprovimin"
msgstr ""
#: pretix/control/forms/filter.py:247
msgid "Follow-up configured"
@@ -13159,7 +13157,7 @@ msgstr ""
#: pretix/control/forms/filter.py:2117
#: pretix/presale/templates/pretixpresale/organizers/customer_giftcards.html:51
msgid "Valid"
msgstr "e vlefshme"
msgstr ""
#: pretix/control/forms/filter.py:2118
msgid "Unredeemed"
@@ -16429,7 +16427,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/event/order_pay_change.html:75
#: pretix/presale/templates/pretixpresale/event/position_change.html:29
msgid "Continue"
msgstr "Vazhdoni"
msgstr ""
#: pretix/control/templates/pretixcontrol/auth/oauth_authorization.html:8
msgid "Authorize an application"
@@ -16677,7 +16675,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/postmessage.html:27
#: pretix/presale/templates/pretixpresale/waiting.html:42
msgid "If this takes longer than a few minutes, please contact us."
msgstr "Nëse kalon më shumë se disa minuta, ju lutemi t'na kontaktoni."
msgstr ""
#: pretix/control/templates/pretixcontrol/boxoffice/payment.html:4
#: pretix/control/templates/pretixcontrol/organizers/devices.html:71
@@ -16907,7 +16905,7 @@ msgstr[1] ""
#: pretix/presale/templates/pretixpresale/event/position_change.html:24
#: pretix/presale/templates/pretixpresale/event/position_modify.html:44
msgid "Cancel"
msgstr "Anuloni"
msgstr ""
#: pretix/control/templates/pretixcontrol/checkin/bulk_revert_confirm.html:27
#: pretix/control/templates/pretixcontrol/checkin/list_delete.html:24
@@ -17021,7 +17019,7 @@ msgstr ""
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/transaction_list.html:14
#: pretix/plugins/checkinlists/exporters.py:770
msgid "Result"
msgstr "Rezultati"
msgstr ""
#: pretix/control/templates/pretixcontrol/checkin/checkins.html:78
#: pretix/control/templates/pretixcontrol/order/index.html:437
@@ -17365,7 +17363,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/checkin/simulator.html:68
msgid "Additional information required"
msgstr "Më shumë informacione kërkohen"
msgstr ""
#: pretix/control/templates/pretixcontrol/checkin/simulator.html:70
msgid ""
@@ -18479,7 +18477,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/event/plugins.html:34
#: pretix/control/templates/pretixcontrol/organizers/plugins.html:34
msgid "Search results"
msgstr "Rezultatet e kërkimit"
msgstr ""
#: pretix/control/templates/pretixcontrol/event/plugins.html:56
#: pretix/control/templates/pretixcontrol/organizers/plugins.html:56
@@ -19745,7 +19743,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:355
#: pretix/control/templates/pretixcontrol/subevents/bulk.html:364
msgid "minutes"
msgstr "minuta"
msgstr ""
#: pretix/control/templates/pretixcontrol/item/index.html:229
msgid "hours"
@@ -21016,7 +21014,7 @@ msgstr ""
#: pretix/plugins/reports/exporters.py:969
#: pretix/presale/templates/pretixpresale/event/fragment_cart.html:469
msgid "Total"
msgstr "Shuma totale"
msgstr ""
#: pretix/control/templates/pretixcontrol/order/index.html:789
#: pretix/presale/templates/pretixpresale/event/order.html:210
@@ -23137,7 +23135,7 @@ msgstr ""
#: pretix/control/templates/pretixcontrol/pdf/index.html:107
msgid "Duplicate"
msgstr "Kopjoni"
msgstr ""
#: pretix/control/templates/pretixcontrol/pdf/index.html:117
msgid "Undo"
@@ -27331,7 +27329,7 @@ msgstr ""
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/transaction_list.html:80
msgid "Comment:"
msgstr "Komente:"
msgstr ""
#: pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/transaction_list.html:98
msgid "No order code detected"
@@ -27574,7 +27572,7 @@ msgstr ""
#: pretix/plugins/paypal2/payment.py:1097
#: pretix/plugins/paypal2/payment.py:1098 pretix/plugins/stripe/payment.py:1816
msgid "PayPal"
msgstr "PayPal"
msgstr ""
#: pretix/plugins/paypal/apps.py:53
msgid ""
@@ -29014,9 +29012,8 @@ msgid "Credit card payments"
msgstr ""
#: pretix/plugins/stripe/payment.py:342 pretix/plugins/stripe/payment.py:1527
#, fuzzy
msgid "iDEAL"
msgstr "iDEAL"
msgstr ""
#: pretix/plugins/stripe/payment.py:344 pretix/plugins/stripe/payment.py:352
#: pretix/plugins/stripe/payment.py:360 pretix/plugins/stripe/payment.py:395
@@ -29035,14 +29032,12 @@ msgid "Alipay"
msgstr ""
#: pretix/plugins/stripe/payment.py:358 pretix/plugins/stripe/payment.py:1564
#, fuzzy
msgid "Bancontact"
msgstr "Bancontact"
msgstr ""
#: pretix/plugins/stripe/payment.py:366
#, fuzzy
msgid "SEPA Direct Debit"
msgstr "Debit direkt me SEPA"
msgstr ""
#: pretix/plugins/stripe/payment.py:369
msgid ""
@@ -29077,14 +29072,12 @@ msgid "Multibanco"
msgstr ""
#: pretix/plugins/stripe/payment.py:409 pretix/plugins/stripe/payment.py:1730
#, fuzzy
msgid "Przelewy24"
msgstr "Przelewy24"
msgstr ""
#: pretix/plugins/stripe/payment.py:417 pretix/plugins/stripe/payment.py:1769
#, fuzzy
msgid "WeChat Pay"
msgstr "WeChat Pay"
msgstr ""
#: pretix/plugins/stripe/payment.py:433 pretix/plugins/stripe/payment.py:1824
msgid "Swish"
@@ -29228,9 +29221,8 @@ msgid "giropay via Stripe"
msgstr ""
#: pretix/plugins/stripe/payment.py:1480
#, fuzzy
msgid "giropay"
msgstr "giropay"
msgstr ""
#: pretix/plugins/stripe/payment.py:1483
msgid ""
@@ -32452,7 +32444,7 @@ msgstr ""
#: pretix/presale/templates/pretixpresale/postmessage.html:21
#: pretix/presale/templates/pretixpresale/waiting.html:22
msgid "We are processing your request …"
msgstr "Ne po e proçesojmë kërkesën tuaj …"
msgstr ""
#: pretix/presale/utils.py:271 pretix/presale/utils.py:417
#: pretix/presale/utils.py:418

View File

@@ -3,159 +3,137 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-11-20 10:37+0000\n"
"PO-Revision-Date: 2025-12-09 22:00+0000\n"
"Last-Translator: Lachlan Struthers <lachlan.struthers@om.org>\n"
"Language-Team: Albanian <https://translate.pretix.eu/projects/pretix/"
"pretix-js/sq/>\n"
"Language: sq\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.14.3\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:68
msgid "Marked as paid"
msgstr "Shënuar se u pagua"
msgstr ""
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:76
msgid "Comment:"
msgstr "Komente:"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:34
msgid "PayPal"
msgstr "PayPal"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:35
msgid "Venmo"
msgstr "Venmo"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:36
#: pretix/static/pretixpresale/js/walletdetection.js:38
#, fuzzy
msgid "Apple Pay"
msgstr "Apple Pay"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:37
#, fuzzy
msgid "Itaú"
msgstr "Itaú"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:38
#, fuzzy
msgid "PayPal Credit"
msgstr "PayPal Credit"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:39
msgid "Credit Card"
msgstr "Kartë Krediti"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:40
msgid "PayPal Pay Later"
msgstr "Bëj PayPal Pay më vonë"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:41
#, fuzzy
msgid "iDEAL"
msgstr "iDEAL"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42
#, fuzzy
msgid "SEPA Direct Debit"
msgstr "Debit direkt me SEPA"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:43
#, fuzzy
msgid "Bancontact"
msgstr "Bancontact"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:44
#, fuzzy
msgid "giropay"
msgstr "giropay"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:45
#, fuzzy
msgid "SOFORT"
msgstr "SOFORT"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:46
#, fuzzy
msgid "eps"
msgstr "eps"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:47
#, fuzzy
msgid "MyBank"
msgstr "MyBank"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:48
#, fuzzy
msgid "Przelewy24"
msgstr "Przelewy24"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:49
#, fuzzy
msgid "Verkkopankki"
msgstr "Verkkopankki"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:50
#, fuzzy
msgid "PayU"
msgstr "PayU"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:51
#, fuzzy
msgid "BLIK"
msgstr "BLIK"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:52
#, fuzzy
msgid "Trustly"
msgstr "Trustly"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:53
#, fuzzy
msgid "Zimpler"
msgstr "Zimpler"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:54
#, fuzzy
msgid "Maxima"
msgstr "Maxima"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:55
#, fuzzy
msgid "OXXO"
msgstr "OXXO"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:56
#, fuzzy
msgid "Boleto"
msgstr "Boleto"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:57
#, fuzzy
msgid "WeChat Pay"
msgstr "WeChat Pay"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:58
#, fuzzy
msgid "Mercado Pago"
msgstr "Mercado Pago"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:167
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:50
#: pretix/static/pretixpresale/js/ui/cart.js:89
msgid "Continue"
msgstr "Vazhdoni"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:225
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:244
@@ -164,224 +142,222 @@ msgstr "Vazhdoni"
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:317
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:341
msgid "Confirming your payment …"
msgstr "Duke e konfirmuar pagesën …"
msgstr ""
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:254
msgid "Payment method unavailable"
msgstr "Metodë e padisponueshme të pagesës"
msgstr ""
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Placed orders"
msgstr "Porositje të bëra"
msgstr ""
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:15
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:39
msgid "Paid orders"
msgstr "Porositje të paguara"
msgstr ""
#: pretix/plugins/statistics/static/pretixplugins/statistics/statistics.js:27
msgid "Total revenue"
msgstr "Të ardhurat totale"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:15
msgid "Contacting Stripe …"
msgstr "Duke e kontaktuar Stripe …"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:72
msgid "Total"
msgstr "Shuma totale"
msgstr ""
#: pretix/plugins/stripe/static/pretixplugins/stripe/pretix-stripe.js:291
msgid "Contacting your bank …"
msgstr "Duke e kontaktuar bankën tuaj …"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:30
msgid "Select a check-in list"
msgstr "Zgjidhni një listë check-in"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:31
msgid "No active check-in lists found."
msgstr "Nuk u gjet asnjë listë check-in."
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:32
msgid "Switch check-in list"
msgstr "Shkëmbeni listë check-in"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:33
msgid "Search results"
msgstr "Rezultatet e kërkimit"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:34
msgid "No tickets found"
msgstr "Nuk u gjetën bileta"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:35
msgid "Result"
msgstr "Rezultati"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:36
msgid "This ticket requires special attention"
msgstr "Kjo biletë duhet kujdes të veçantë"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:37
msgid "Switch direction"
msgstr "Ndryshoni drejtimin"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:38
msgid "Entry"
msgstr "Hyrje"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:39
msgid "Exit"
msgstr "Dalje"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:40
msgid "Scan a ticket or search and press return…"
msgstr "Skanoni një biletë ose kërkoni dhe shtypni butonin 'Enter'…"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:41
msgid "Load more"
msgstr "Ngarkoni më shumë"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:42
msgid "Valid"
msgstr "e vlefshme"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:43
msgid "Unpaid"
msgstr "e papaguar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:44
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:45
msgid "Canceled"
msgstr "e anuluar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:46
msgid "Confirmed"
msgstr "e konfirmuar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:47
msgid "Approval pending"
msgstr "Duke pritur aprovimin"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:48
msgid "Redeemed"
msgstr "e përdorur"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:49
msgid "Cancel"
msgstr "Anuloni"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:51
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:60
msgid "Ticket not paid"
msgstr "Bileta nuk është paguar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:52
msgid "This ticket is not yet paid. Do you want to continue anyways?"
msgstr "Kjo biletë ende nuk është paguar. A dëshironi të vazhdoni gjithsesi?"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:53
msgid "Additional information required"
msgstr "Më shumë informacione kërkohen"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:54
msgid "Valid ticket"
msgstr "Biletë të vlefshme"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:55
msgid "Exit recorded"
msgstr "Dalja u regjistrua"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:56
msgid "Ticket already used"
msgstr "Bileta tashmë është përdorur"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:57
msgid "Information required"
msgstr "Informacion i domosdoshëm"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:58
msgid "Unknown ticket"
msgstr "Biletë e panjohur"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:59
msgid "Ticket type not allowed here"
msgstr "Ky lloj bilete nuk lejohet këtu"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:61
msgid "Entry not allowed"
msgstr "Hyrja nuk lejohet"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:62
msgid "Ticket code revoked/changed"
msgstr "Kodi i biletës është anuluar/ndryshuar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:63
msgid "Ticket blocked"
msgstr "Bileta u bllokua"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:64
msgid "Ticket not valid at this time"
msgstr "Bileta nuk është e vlefshme për momentin"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:65
msgid "Order canceled"
msgstr "Porositja ësthë anuluar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:66
msgid "Ticket code is ambiguous on list"
msgstr "Kodi i biletës është e paqartë në listë"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:67
msgid "Order not approved"
msgstr "Porositje nuk është aprovuar"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:68
msgid "Checked-in Tickets"
msgstr "Bileta të regjistruara"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:69
msgid "Valid Tickets"
msgstr "Bileta të vlefshme"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:70
msgid "Currently inside"
msgstr "Aktualisht brenda"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:71
#: pretix/static/pretixcontrol/js/ui/question.js:136
#: pretix/static/pretixpresale/js/ui/questions.js:271
msgid "Yes"
msgstr "Po"
msgstr ""
#: pretix/plugins/webcheckin/static/pretixplugins/webcheckin/main.js:72
#: pretix/static/pretixcontrol/js/ui/question.js:137
#: pretix/static/pretixpresale/js/ui/questions.js:271
msgid "No"
msgstr "Jo"
msgstr ""
#: pretix/static/lightbox/js/lightbox.js:96
msgid "close"
msgstr "Mbyllni"
msgstr ""
#: pretix/static/pretixbase/js/addressform.js:98
#: pretix/static/pretixpresale/js/ui/main.js:529
msgid "required"
msgstr "të domosdoshme"
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:13
msgid ""
"Your request is currently being processed. Depending on the size of your "
"event, this might take up to a few minutes."
msgstr ""
"Këkesa juaj po proçesohet tani. Në varësi të masës së eventit tuaj, mund të "
"kërkojë disa minuta."
#: pretix/static/pretixbase/js/asynctask.js:17
msgid "Your request has been queued on the server and will soon be processed."
msgstr "Kërkesa juaj është në pritje në server dhe do të proçesohet së shpejti."
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:21
msgid ""
@@ -389,41 +365,34 @@ msgid ""
"If this takes longer than two minutes, please contact us or go back in your "
"browser and try again."
msgstr ""
"Kërkesa juaj arriti në server por ende presim të proçesohet. Nëse kalon më "
"shumë se dy minuta, ju lutemi t'na kontaktoni ose të ktheheni më përpara dhe "
"të provoni përsëri."
#: pretix/static/pretixbase/js/asynctask.js:125
#: pretix/static/pretixbase/js/asynctask.js:182
#: pretix/static/pretixbase/js/asynctask.js:186
#: pretix/static/pretixcontrol/js/ui/mail.js:24
msgid "An error of type {code} occurred."
msgstr "Një gabim të llojit {kodi} ka ndodhur."
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:128
msgid ""
"We currently cannot reach the server, but we keep trying. Last error code: "
"{code}"
msgstr ""
"Nuk mund t'a kontaktojmë serverin për momentin, por vazhdojmë t'a provojmë. "
"Kodi gabimi i fundit: {kodi}"
#: pretix/static/pretixbase/js/asynctask.js:162
#: pretix/static/pretixcontrol/js/ui/mail.js:21
msgid "The request took too long. Please try again."
msgstr "Kërkesa juaj kërkonte tepër kohë. Ju lutemi të provoni përsëri."
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:188
#: pretix/static/pretixcontrol/js/ui/mail.js:26
msgid ""
"We currently cannot reach the server. Please try again. Error code: {code}"
msgstr ""
"Nuk mund t'a kontaktojmë serverin për momentin. Ju lutemi, provoni përsëri. "
"Kodi gabimi i fundit: {kodi}"
#: pretix/static/pretixbase/js/asynctask.js:216
msgid "We are processing your request …"
msgstr "Ne po e proçesojmë kërkesën tuaj …"
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:219
msgid ""
@@ -431,169 +400,166 @@ msgid ""
"than one minute, please check your internet connection and then reload this "
"page and try again."
msgstr ""
"Tani po e dërgojmë kërkesën tuaj në server. Nëse kalon më shumë se një "
"minutë, ju lutemi t'a kontrolloni lidhjen tuaj në internet dhe pastak t'a "
"rifreskoni këtë faqe që të provoni përsëri."
#: pretix/static/pretixbase/js/asynctask.js:276
msgid "If this takes longer than a few minutes, please contact us."
msgstr "Nëse kalon më shumë se disa minuta, ju lutemi t'na kontaktoni."
msgstr ""
#: pretix/static/pretixbase/js/asynctask.js:331
msgid "Close message"
msgstr "Mbyllni mesazhin"
msgstr ""
#: pretix/static/pretixcontrol/js/clipboard.js:23
msgid "Copied!"
msgstr "E kopjuar!"
msgstr ""
#: pretix/static/pretixcontrol/js/clipboard.js:29
msgid "Press Ctrl-C to copy!"
msgstr "Shtypni Ctrl+C për të kopjuar!"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:12
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:18
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:24
msgid "is one of"
msgstr "është një nga"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:30
msgid "is before"
msgstr "është para"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:34
msgid "is after"
msgstr "është pas"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:40
msgid "="
msgstr "="
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:99
msgid "Product"
msgstr "Produkti"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:103
msgid "Product variation"
msgstr "Varianti i produktit"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:107
msgid "Gate"
msgstr "Porta"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:111
msgid "Current date and time"
msgstr "Datë dhe orë aktuale"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:115
msgid "Current day of the week (1 = Monday, 7 = Sunday)"
msgstr "Dita aktuale e javës (1 = Të hënën, 7 = Të dielën)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:119
msgid "Current entry status"
msgstr "Gjendja aktuale e hyrjes"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:123
msgid "Number of previous entries"
msgstr "Shuma e hyrjeve të mëparshme"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:127
msgid "Number of previous entries since midnight"
msgstr "Shuma e hyrjeve të mëparshme nga mesnata"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:131
msgid "Number of previous entries since"
msgstr "Shuma e hyrjeve të mëparshme nga"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:135
msgid "Number of previous entries before"
msgstr "Shuma e hyrjeve të mëparshme përpara"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:139
msgid "Number of days with a previous entry"
msgstr "Shuma e ditëve me një hyrje të mëparshme"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:143
msgid "Number of days with a previous entry since"
msgstr "Shuma e ditëve me një hyrje të mëparshme nga"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:147
msgid "Number of days with a previous entry before"
msgstr "Shuma e ditëve me një hyrje të mëparshme përpara"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:151
msgid "Minutes since last entry (-1 on first entry)"
msgstr "Minuta nga hyrja e fundit (-1 në hyrjen e parë)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:155
msgid "Minutes since first entry (-1 on first entry)"
msgstr "Minuta nga hyrja e parë (-1 në hyrjen e parë)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:182
msgid "All of the conditions below (AND)"
msgstr "Të gjitha gjendjet më poshtë (DHE)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:183
msgid "At least one of the conditions below (OR)"
msgstr "Të paktën një nga gjendjet më poshtë (OSE)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:184
msgid "Event start"
msgstr "Fillimi i eventit"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:185
msgid "Event end"
msgstr "Mbarimi i eventit"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:186
msgid "Event admission"
msgstr "Hyrja në event"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:187
msgid "custom date and time"
msgstr "datë dhe orë e kustomizuar"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:188
msgid "custom time"
msgstr "orë e kustomizuar"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:189
msgid "Tolerance (minutes)"
msgstr "Toleranca (minuta)"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:190
msgid "Add condition"
msgstr "Shtoni gjendje"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:191
msgid "minutes"
msgstr "minuta"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:192
msgid "Duplicate"
msgstr "Kopjoni"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:193
msgctxt "entry_status"
msgid "present"
msgstr "pranishëm"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:194
msgctxt "entry_status"
msgid "absent"
msgstr "munguar"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:289
msgid "Error: Product not found!"
msgstr "Gabim: Produkti nuk u gjet!"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:296
msgid "Error: Variation not found!"
msgstr "Gabim: Varianti nuk u gjet!"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/editor.js:171
msgid "Check-in QR"
msgstr "Kodi QR për check-in"
msgstr ""
#: pretix/static/pretixcontrol/js/ui/editor.js:549
msgid "The PDF background file could not be loaded for the following reason:"

View File

@@ -1,71 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
from django.utils.translation import gettext_lazy as _
from lxml import etree
def parse(file):
# Spec: https://www.ebics.de/de/datenformate
data = file.read()
root = etree.fromstring(data)
statements = root.findall("{*}BkToCstmrStmt/{*}Stmt")
if not statements:
raise ValueError(_("Empty file or unknown format."))
def get_text(findall_result):
if len(findall_result) == 1:
return findall_result[0].text
return ""
rows = []
for stmt in statements:
for ntry in stmt.findall("{*}Ntry"):
minus = ""
otherparty = "Dbtr"
if ntry.findall("{*}CdtDbtInd")[0].text == "DBIT":
otherparty = "Cdtr"
minus = "-"
reference_parts = [
get_text(ntry.findall("{*}NtryDtls/{*}TxDtls/{*}RmtInf/{*}Ustrd")),
get_text(ntry.findall("{*}NtryDtls/{*}TxDtls/{*}Refs/{*}EndToEndId")),
get_text(ntry.findall("{*}NtryDtls/{*}TxDtls/{*}Refs/{*}InstructionIdentification")),
]
if ntry.findall("{*}NtryDtls/{*}Btch"):
# Batch booking, we do not support splitting yet
reference_parts.insert(0, get_text(ntry.findall("{*}NtryDtls/{*}Btch/{*}PmtInfId")))
row = {
'amount': minus + ntry.findall("{*}Amt")[0].text,
'date': get_text(ntry.findall("{*}BookgDt/{*}Dt")),
'reference': "\n".join(filter(lambda a: bool(a) and a != "NOTPROVIDED", reference_parts))
}
if ext_id := get_text(ntry.findall("{*}AcctSvcrRef")):
row['external_id'] = ext_id
if iban := get_text(ntry.findall(f"{{*}}NtryDtls/{{*}}TxDtls/{{*}}RltdPties/{{*}}{otherparty}Acct/{{*}}Id/{{*}}IBAN")):
row['iban'] = iban
if bic := get_text(ntry.findall(f"{{*}}NtryDtls/{{*}}TxDtls/{{*}}RltdAgts/{{*}}{otherparty}Agt/{{*}}FinInstnId/{{*}}BICFI")):
row['bic'] = bic
if payer := get_text(ntry.findall(f"{{*}}NtryDtls/{{*}}TxDtls/{{*}}RltdPties/{{*}}{otherparty}/{{*}}Nm")):
row['payer'] = payer
rows.append(row)
return rows

View File

@@ -66,7 +66,7 @@ from pretix.control.permissions import (
)
from pretix.control.views.organizer import OrganizerDetailViewMixin
from pretix.helpers.json import CustomJSONEncoder
from pretix.plugins.banktransfer import camtimport, csvimport, mt940import
from pretix.plugins.banktransfer import csvimport, mt940import
from pretix.plugins.banktransfer.models import (
BankImportJob, BankTransaction, RefundExport,
)
@@ -419,9 +419,6 @@ class ImportView(ListView):
):
return self.process_mt940()
elif 'file' in self.request.FILES and '.xml' in self.request.FILES.get('file').name.lower():
return self.process_camt()
elif self.request.FILES.get('file') is None:
messages.error(self.request, _('You must choose a file to import.'))
return self.redirect_back()
@@ -435,14 +432,6 @@ class ImportView(ListView):
def settings(self):
return SettingsSandbox('payment', 'banktransfer', getattr(self.request, 'event', self.request.organizer))
def process_camt(self):
try:
return self.start_processing(camtimport.parse(self.request.FILES.get('file')))
except:
logger.exception('Failed to import CAMT file')
messages.error(self.request, _('We were unable to process your input.'))
return self.redirect_back()
def process_mt940(self):
try:
return self.start_processing(mt940import.parse(self.request.FILES.get('file')))

View File

@@ -137,7 +137,7 @@ logger = logging.getLogger('pretix.plugins.stripe')
# Real-time payments
# - Swish: ✓
# - PayNow: ✗
# - PromptPay:
# - PromptPay:
# - Pix: ✗
#
# Vouchers
@@ -440,14 +440,6 @@ class StripeSettingsHolder(BasePaymentProvider):
'before they work properly.'),
required=False,
)),
('method_promptpay',
forms.BooleanField(
label='PromptPay',
disabled=self.event.currency != 'THB',
help_text=_('Some payment methods might need to be enabled in the settings of your Stripe account '
'before they work properly.'),
required=False,
)),
('method_swish',
forms.BooleanField(
label=_('Swish'),
@@ -1888,30 +1880,6 @@ class StripeSwish(StripeRedirectMethod):
}
class StripePromptPay(StripeRedirectMethod):
identifier = 'stripe_promptpay'
verbose_name = _('PromptPay via Stripe')
public_name = 'PromptPay'
method = 'promptpay'
confirmation_method = 'automatic'
explanation = _(
'This payment method is available to PromptPay users in Thailand. Please have your app ready.'
)
def is_allowed(self, request: HttpRequest, total: Decimal=None) -> bool:
return super().is_allowed(request, total) and request.event.currency == "THB"
def _payment_intent_kwargs(self, request, payment):
return {
"payment_method_data": {
"type": "promptpay",
"billing_details": {
"email": payment.order.email,
},
},
}
class StripeTwint(StripeRedirectMethod):
identifier = 'stripe_twint'
verbose_name = _('TWINT via Stripe')

View File

@@ -46,17 +46,15 @@ def register_payment_provider(sender, **kwargs):
from .payment import (
StripeAffirm, StripeAlipay, StripeBancontact, StripeCC, StripeEPS,
StripeGiropay, StripeIdeal, StripeKlarna, StripeMobilePay,
StripeMultibanco, StripePayByBank, StripePayPal, StripePromptPay,
StripePrzelewy24, StripeRevolutPay, StripeSEPADirectDebit,
StripeSettingsHolder, StripeSofort, StripeSwish, StripeTwint,
StripeWeChatPay,
StripeMultibanco, StripePayByBank, StripePayPal, StripePrzelewy24,
StripeRevolutPay, StripeSEPADirectDebit, StripeSettingsHolder,
StripeSofort, StripeSwish, StripeTwint, StripeWeChatPay,
)
return [
StripeSettingsHolder, StripeCC, StripeGiropay, StripeIdeal, StripeAlipay, StripeBancontact,
StripeSofort, StripeEPS, StripeMultibanco, StripePayByBank, StripePrzelewy24, StripePromptPay, StripeRevolutPay,
StripeWeChatPay, StripeSEPADirectDebit, StripeAffirm, StripeKlarna, StripePayPal, StripeSwish,
StripeTwint, StripeMobilePay
StripeSofort, StripeEPS, StripeMultibanco, StripePrzelewy24, StripeRevolutPay, StripeWeChatPay,
StripeSEPADirectDebit, StripeAffirm, StripeKlarna, StripePayByBank, StripePayPal, StripeSwish, StripeTwint, StripeMobilePay
]

View File

@@ -79,9 +79,3 @@
.vcenter {
margin: auto;
}
.stripe-qr-code {
max-width: 80%;
width: 200px;
height: auto;
}

View File

@@ -325,8 +325,6 @@ $(function () {
} else if ($("#stripe_payment_intent_next_action_redirect_url").length) {
let payment_intent_next_action_redirect_url = $.trim($("#stripe_payment_intent_next_action_redirect_url").html());
pretixstripe.handlePaymentRedirectAction(payment_intent_next_action_redirect_url);
} else if ($.trim($("#stripe_payment_intent_action_type").html()) === "promptpay_display_qr_code") {
waitingDialog.hide();
} else if ($.trim($("#stripe_payment_intent_action_type").html()) === "wechat_pay_display_qr_code") {
let payment_intent_client_secret = $.trim($("#stripe_payment_intent_client_secret").html());
pretixstripe.handleWechatAction(payment_intent_client_secret);

View File

@@ -27,21 +27,9 @@
<div class="stripe-errors sr-only panel-body">
</div>
{% if payment_intent_promptpay_image_url %}
<div class="panel-body">
<p>{% blocktrans trimmed %}
Please scan the QR code below to complete your PromptPay payment.
Once you have completed your payment, you can refresh this page.
{% endblocktrans %}</p>
<div class="text-center">
<img src="{{ payment_intent_promptpay_image_url }}" alt="{% trans 'PromptPay QR code' %}"
class="stripe-qr-code" />
</div>
</div>
{% else %}
<div class="panel-body embed-responsive embed-responsive-sca" id="scacontainer">
</div>
{% endif %}
<div class="panel-body embed-responsive embed-responsive-sca" id="scacontainer">
</div>
</div>
<div class="row checkout-button-row">
<div class="col-md-4">

View File

@@ -613,7 +613,7 @@ class ScaView(StripeOrderView, View):
if intent.status == 'requires_action' and intent.next_action.type in [
'use_stripe_sdk', 'redirect_to_url', 'alipay_handle_redirect', 'wechat_pay_display_qr_code',
'swish_handle_redirect_or_display_qr_code', 'multibanco_display_details', 'promptpay_display_qr_code',
'swish_handle_redirect_or_display_qr_code', 'multibanco_display_details',
]:
ctx = {
'order': self.order,
@@ -631,8 +631,6 @@ class ScaView(StripeOrderView, View):
elif intent.next_action.type == 'multibanco_display_details':
ctx['payment_intent_next_action_redirect_url'] = intent.next_action.multibanco_display_details['hosted_voucher_url']
ctx['payment_intent_redirect_action_handling'] = 'iframe'
elif intent.next_action.type == 'promptpay_display_qr_code':
ctx['payment_intent_promptpay_image_url'] = intent.next_action.promptpay_display_qr_code['image_url_svg']
r = render(request, 'pretixplugins/stripe/sca.html', ctx)
r._csp_ignore = True

View File

@@ -435,7 +435,7 @@ def cart_session(request):
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class CartApplyVoucher(EventViewMixin, CartActionMixin, AsyncAction, View):
task = apply_voucher
known_errortypes = ['CartError']
known_errortypes = ['CartError', 'CartPositionError']
def get_success_message(self, value):
return _('We applied the voucher to as many products in your cart as we could.')
@@ -513,7 +513,7 @@ class CartApplyVoucher(EventViewMixin, CartActionMixin, AsyncAction, View):
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class CartRemove(EventViewMixin, CartActionMixin, AsyncAction, View):
task = remove_cart_position
known_errortypes = ['CartError']
known_errortypes = ['CartError', 'CartPositionError']
def get_success_message(self, value):
if CartPosition.objects.filter(cart_id=get_or_create_cart_id(self.request)).exists():
@@ -542,7 +542,7 @@ class CartRemove(EventViewMixin, CartActionMixin, AsyncAction, View):
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class CartClear(EventViewMixin, CartActionMixin, AsyncAction, View):
task = clear_cart
known_errortypes = ['CartError']
known_errortypes = ['CartError', 'CartPositionError']
def get_success_message(self, value):
create_empty_cart_id(self.request)
@@ -556,7 +556,7 @@ class CartClear(EventViewMixin, CartActionMixin, AsyncAction, View):
@method_decorator(allow_frame_if_namespaced, 'dispatch')
class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
task = extend_cart_reservation
known_errortypes = ['CartError']
known_errortypes = ['CartError', 'CartPositionError']
def _ajax_response_data(self, value):
if isinstance(value, dict):
@@ -566,7 +566,11 @@ class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
def get_success_message(self, value):
if value['success'] > 0:
return _('Your cart timeout was extended.')
if value.get('price_changed'):
return _('Your cart timeout was extended. Please note that some of the prices in your cart '
'changed.')
else:
return _('Your cart timeout was extended.')
def post(self, request, *args, **kwargs):
return self.do(self.request.event.id, get_or_create_cart_id(self.request), translation.get_language(),
@@ -578,7 +582,7 @@ class CartExtendReservation(EventViewMixin, CartActionMixin, AsyncAction, View):
@method_decorator(iframe_entry_view_wrapper, 'dispatch')
class CartAdd(EventViewMixin, CartActionMixin, AsyncAction, View):
task = add_items_to_cart
known_errortypes = ['CartError']
known_errortypes = ['CartError', 'CartPositionError']
def get_success_message(self, value):
return _('The products have been successfully added to your cart.')

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 163 KiB

View File

@@ -745,6 +745,8 @@ def test_use_membership(event, customer, membership, requiring_ticket):
item=requiring_ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123",
used_membership=membership
)
q = event.quotas.create(size=None, name="foo")
q.items.add(requiring_ticket)
order = _create_order(event, email='dummy@example.org', positions=[cp1],
now_dt=now(),
sales_channel=event.organizer.sales_channels.get(identifier="web"),
@@ -767,6 +769,8 @@ def test_use_membership_invalid(event, customer, membership, requiring_ticket):
membership.date_start -= timedelta(days=100)
membership.date_end -= timedelta(days=100)
membership.save()
q = event.quotas.create(size=None, name="foo")
q.items.add(requiring_ticket)
cp1 = CartPosition.objects.create(
item=requiring_ticket, price=23, expires=now() + timedelta(days=1), event=event, cart_id="123",
used_membership=membership

View File

@@ -1,756 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Beispielnachricht_camt.053_BankToCustomerStatement_via_EBICS-->
<!-- Source https://www.bundesbank.de/de/startseite/beispieldateien-zur-bereitstellung-der-elektronischen-kontoinformationen-zu-dotationskonten-von-banken-im-format-camt-052-und-camt-053-bei-kommunikation-via-ebics-example-files-for-the-provision-of-electronic-account-information-for-cash-handling-accounts-of-banks-in-camt-052-and-camt-053-format-when-communicating-via-ebics-943090 -->
<Document xmlns:n0="urn:iso:std:iso:20022:tech:xsd:camt.053.001.08">
<BkToCstmrStmt>
<GrpHdr>
<MsgId>20240313C0098170</MsgId>
<CreDtTm>2024-03-13T18:40:42.8734727+01:00</CreDtTm>
</GrpHdr>
<Stmt>
<Id>20240313C0098170</Id>
<StmtPgntn>
<PgNb>00001</PgNb>
<LastPgInd>true</LastPgInd>
</StmtPgntn>
<ElctrncSeqNb>1</ElctrncSeqNb>
<CreDtTm>2024-03-13T18:40:42.8734727+01:00</CreDtTm>
<Acct>
<Id>
<IBAN>DE00IBANdesDotationskontos</IBAN>
</Id>
<Tp>
<Cd>CACC</Cd>
</Tp>
<Ccy>EUR</Ccy>
<Nm>Testbank, Hamburg</Nm>
<Ownr>
<Nm>Testbank-Inhaber</Nm>
</Ownr>
<Svcr>
<FinInstnId>
<BICFI>MARKDEF1200</BICFI>
<ClrSysMmbId>
<ClrSysId>
<Cd>DEBLZ</Cd>
</ClrSysId>
<MmbId>20000000</MmbId>
</ClrSysMmbId>
<Nm>Deutsche Bundesbank</Nm>
<Othr>
<Id>DE114103555</Id>
<Issr>UmsStId</Issr>
</Othr>
</FinInstnId>
<BrnchId>
<Nm>Filiale Hamburg</Nm>
</BrnchId>
</Svcr>
</Acct>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>OPBD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="EUR">0.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2024-03-13</Dt>
</Dt>
</Bal>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>CLBD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="EUR">0.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2024-03-13</Dt>
</Dt>
</Bal>
<Ntry>
<NtryRef>2000000011240313</NtryRef>
<Amt Ccy="EUR">100000.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>103600002791/0019200002</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>CNTR</Cd>
<SubFmlyCd>CDPT</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCMI+082+0019200002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>2000000011240313</AcctSvcrRef>
</Refs>
<Amt Ccy="EUR">100000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>CNTR</Cd>
<SubFmlyCd>CDPT</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCMI+082+0019200002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Einzahlung</Prtry>
</Purp>
<AddtlTxInf>Einzahlungen</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Einzahlungen</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>2000000012240313</NtryRef>
<Amt Ccy="EUR">25000.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>049000039704/0019000002</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>CNTR</Cd>
<SubFmlyCd>CWDL</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCMI+083+0019000002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>2000000012240313</AcctSvcrRef>
<InstrId>9998770</InstrId>
<ChqNb>9998770</ChqNb>
</Refs>
<Amt Ccy="EUR">25000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>CNTR</Cd>
<SubFmlyCd>CWDL</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCMI+083+0019000002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Auszahlung</Prtry>
</Purp>
<AddtlTxInf>Auszahlungen</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Auszahlungen</AddtlNtryInf>
</Ntry>
<Ntry>
<Amt Ccy="EUR">20000.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>047200003598/0002000001</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICHQ</Cd>
<SubFmlyCd>CCHQ</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCHK+101+0002000001</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<InstrId>9998771</InstrId>
<ChqNb>9998771</ChqNb>
</Refs>
<Amt Ccy="EUR">250000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICHQ</Cd>
<SubFmlyCd>CCHQ</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCHK+101+0002000001</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Cdtr>
<Pty>
<Nm>Deutsche Bundesbank KBS HMS Hamburg</Nm>
</Pty>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE98200000000020002633</IBAN>
</Id>
</CdtrAcct>
</RltdPties>
<RltdAgts>
<CdtrAgt>
<FinInstnId>
<ClrSysMmbId>
<ClrSysId>
<Cd>DEBLZ</Cd>
</ClrSysId>
<MmbId>20000000</MmbId>
</ClrSysMmbId>
</FinInstnId>
</CdtrAgt>
</RltdAgts>
<Purp>
<Prtry>LS bestätigter Scheck</Prtry>
</Purp>
<RmtInf>
<Ustrd>Bestätigter Scheck vom 13.03.2024</Ustrd>
<Ustrd>Scheck Nr. 135469</Ustrd>
</RmtInf>
<AddtlTxInf>Inhaberscheck</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Inhaberscheck</AddtlNtryInf>
</Ntry>
<Ntry>
<Amt Ccy="EUR">15.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>047200003598/0002000001</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>ACMT</Cd>
<Fmly>
<Cd>MDOP</Cd>
<SubFmlyCd>CHRG</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCHG+808+0002000001</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Amt Ccy="EUR">15.00</Amt>
<BkTxCd>
<Domn>
<Cd>ACMT</Cd>
<Fmly>
<Cd>MDOP</Cd>
<SubFmlyCd>CHRG</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NCHG+808+0002000001</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>LS Entgelte Giro, SchE</Prtry>
</Purp>
<AddtlTxInf>Gebühren</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Gebühren</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>H202403135000000107</NtryRef>
<Amt Ccy="EUR">145015.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>051500000059/0019000003</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019000003</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>H202403135000000107</AcctSvcrRef>
<InstrId>H202403135000000107</InstrId>
</Refs>
<Amt Ccy="EUR">145015.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019000003</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<AddtlTxInf>Überweisungsgutschrift mit Festvaluta</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Überweisungsgutschrift mit Festvaluta</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>H202403135000000108</NtryRef>
<Amt Ccy="EUR">50000.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>105600004525/0019200003</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019200003</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>H202403135000000108</AcctSvcrRef>
<InstrId>H202403135000000108</InstrId>
</Refs>
<Amt Ccy="EUR">50000.00</Amt>
<AmtDtls>
<InstdAmt>
<Amt Ccy="EUR">50000.00</Amt>
</InstdAmt>
</AmtDtls>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019200003</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Pty>
<Nm>Testbank</Nm>
</Pty>
</Dbtr>
<DbtrAcct>
<Id>
<Othr>
<Id>0123456789</Id>
</Othr>
</Id>
</DbtrAcct>
</RltdPties>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<RmtInf>
<Ustrd>VWZ pacs008 RTGS nach DOTA</Ustrd>
</RmtInf>
<AddtlTxInf>Überweisungsgutschrift mit Festvaluta</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Überweisungsgutschrift mit Festvaluta</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>H202403135000000109</NtryRef>
<Amt Ccy="EUR">80000.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>051800000156/0019000004</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019000004</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>H202403135000000109</AcctSvcrRef>
<InstrId>pacs009-EndToEndId-00004</InstrId>
</Refs>
<Amt Ccy="EUR">80000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+088+0019000004</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<RmtInf>
<Ustrd>VWZ pacs009 RTGS nach DOTA</Ustrd>
</RmtInf>
<AddtlTxInf>Überweisungsgutschrift mit Festvaluta</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Überweisungsgutschrift mit Festvaluta</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>pacs009-InstrId-00005</NtryRef>
<Amt Ccy="EUR">30000.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>055100000086/0019000005</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000005</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>pacs009-InstrId-00005</AcctSvcrRef>
<InstrId>pacs009-InstrId-00005</InstrId>
</Refs>
<Amt Ccy="EUR">30000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000005</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<RmtInf>
<Ustrd>VWZ pacs009 DOTA nach MCA</Ustrd>
</RmtInf>
<AddtlTxInf>Eilüberweisung</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Eilüberweisung</AddtlNtryInf>
</Ntry>
<Ntry>
<NtryRef>pacs009-InstrId-00006</NtryRef>
<Amt Ccy="EUR">120000.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>001400001221/0019000006</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000006</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>pacs009-InstrId-00006</AcctSvcrRef>
<InstrId>pacs009-InstrId-00006</InstrId>
</Refs>
<Amt Ccy="EUR">120000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000006</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<RmtInf>
<Ustrd>VWZ pacs009 DOTA nach RTGS</Ustrd>
</RmtInf>
<AddtlTxInf>Eilüberweisung</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Eilüberweisung</AddtlNtryInf>
</Ntry>
<Ntry>
<Amt Ccy="EUR">100000.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>016900004681/0002000002</AcctSvcrRef>
<BkTxCd>
<Prtry>
<Cd>NCHK+070+0002000002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Amt Ccy="EUR">100000.00</Amt>
<BkTxCd>
<Prtry>
<Cd>NCHK+070+0002000002</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Pty>
<Nm>Deutsche Bundesbank / 22772 Hamburg</Nm>
</Pty>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>DE98200000000020002633</IBAN>
</Id>
</DbtrAcct>
</RltdPties>
<RltdAgts>
<DbtrAgt>
<FinInstnId>
<ClrSysMmbId>
<ClrSysId>
<Cd>DEBLZ</Cd>
</ClrSysId>
<MmbId>20000000</MmbId>
</ClrSysMmbId>
</FinInstnId>
</DbtrAgt>
</RltdAgts>
<Purp>
<Prtry>GS bestätigter Scheck</Prtry>
</Purp>
<RmtInf>
<Ustrd>Rückgabe Best. Scheck vom 28.02.2024</Ustrd>
<Ustrd>Scheck Nr. 135468</Ustrd>
</RmtInf>
</TxDtls>
</NtryDtls>
</Ntry>
<Ntry>
<NtryRef>pacs008-InstrId-00007</NtryRef>
<Amt Ccy="EUR">280000.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>
<Cd>BOOK</Cd>
</Sts>
<BookgDt>
<Dt>2024-03-13</Dt>
</BookgDt>
<ValDt>
<Dt>2024-03-13</Dt>
</ValDt>
<AcctSvcrRef>010300005153/0019000007</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000007</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<NtryDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>pacs008-InstrId-00007</AcctSvcrRef>
<InstrId>pacs008-InstrId-00007</InstrId>
</Refs>
<Amt Ccy="EUR">280000.00</Amt>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>ICDT</Cd>
<SubFmlyCd>SDVA</SubFmlyCd>
</Fmly>
</Domn>
<Prtry>
<Cd>NTRF+087+0019000007</Cd>
<Issr>DK</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Cdtr>
<Pty>
<Nm>Testbank, Hamburg</Nm>
</Pty>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE00IBANbeiTestbank</IBAN>
</Id>
</CdtrAcct>
</RltdPties>
<Purp>
<Prtry>Überw Prior1/SWI</Prtry>
</Purp>
<RmtInf>
<Ustrd>VWZ pacs008 DOTA nach RTGS</Ustrd>
</RmtInf>
<AddtlTxInf>Eilüberweisung</AddtlTxInf>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>Eilüberweisung</AddtlNtryInf>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>

View File

@@ -1,312 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02 camt.053.001.02.xsd">
<BkToCstmrStmt>
<GrpHdr>
<MsgId>053D2013-12-27T22:05:03.0N130000005</MsgId>
<CreDtTm>2013-12-27T22:04:52.0+01:00</CreDtTm>
<MsgPgntn>
<PgNb>1</PgNb>
<LastPgInd>true</LastPgInd>
</MsgPgntn>
</GrpHdr>
<Stmt>
<Id>0352C5320131227220503</Id>
<ElctrncSeqNb>130000005</ElctrncSeqNb>
<CreDtTm>2013-12-27T22:04:52.0+01:00</CreDtTm>
<Acct>
<Id>
<IBAN>DE14740618130000033626</IBAN>
</Id>
<Ccy>EUR</Ccy>
<Ownr>
<Nm>Testkonto Nummer 1</Nm>
</Ownr>
<Svcr>
<FinInstnId>
<BIC>GENODEF1PFK</BIC>
<Nm>VR-Bank Rottal-Inn eG</Nm>
<Othr>
<Id>DE 129267947</Id>
<Issr>UmsStId</Issr>
</Othr>
</FinInstnId>
</Svcr>
</Acct>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>PRCD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="EUR">33.06</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2013-12-27</Dt>
</Dt>
</Bal>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>CLBD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="EUR">23.06</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2013-12-27</Dt>
</Dt>
</Bal>
<Ntry>
<Amt Ccy="EUR">2.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-12-27</Dt>
</BookgDt>
<ValDt>
<Dt>2013-12-27</Dt>
</ValDt>
<AcctSvcrRef>2013122710583450000</AcctSvcrRef>
<BkTxCd/>
<NtryDtls>
<TxDtls>
<BkTxCd>
<Prtry>
<Cd>NTRF+020</Cd>
<Issr>ZKA</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Cdtr>
<Nm>Testkonto Nummer 2</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<Othr>
<Id> 740618130100033626</Id>
<SchmeNm>
<Cd>BBAN</Cd>
</SchmeNm>
</Othr>
</Id>
</CdtrAcct>
</RltdPties>
<RmtInf>
<Ustrd>TEST BERWEISUNG MITTELS BLZUND KONTONUMMER - DTA</Ustrd>
</RmtInf>
</TxDtls>
</NtryDtls>
</Ntry>
<Ntry>
<Amt Ccy="EUR">3.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-12-27</Dt>
</BookgDt>
<ValDt>
<Dt>2013-12-27</Dt>
</ValDt>
<AcctSvcrRef>2013122710583600000</AcctSvcrRef>
<BkTxCd/>
<NtryDtls>
<TxDtls>
<Refs>
<MsgId>CCTI/VRNWSW/b044f24cddb92a502b8a1b5</MsgId>
<EndToEndId>NOTPROVIDED</EndToEndId>
</Refs>
<BkTxCd>
<Prtry>
<Cd>NMSC+201</Cd>
<Issr>ZKA</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Testkonto Nummer 1</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>DE14740618130000033626</IBAN>
</Id>
</DbtrAcct>
<UltmtDbtr>
<Nm>keine Information vorhanden</Nm>
</UltmtDbtr>
<Cdtr>
<Nm>Testkonto Nummer 2</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE58740618130100033626</IBAN>
</Id>
</CdtrAcct>
<UltmtCdtr>
<Nm>keine Information vorhanden</Nm>
</UltmtCdtr>
</RltdPties>
<RltdAgts>
<CdtrAgt>
<FinInstnId>
<BIC>GENODEF1PFK</BIC>
</FinInstnId>
</CdtrAgt>
</RltdAgts>
<RmtInf>
<Ustrd>Test+berweisung mit BIC und IBAN SEPA IBAN: DE58740618130100033626 BIC: GENODEF1PFK</Ustrd>
</RmtInf>
</TxDtls>
</NtryDtls>
</Ntry>
<Ntry>
<Amt Ccy="EUR">1.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-12-27</Dt>
</BookgDt>
<ValDt>
<Dt>2013-12-27</Dt>
</ValDt>
<AcctSvcrRef>2013122711085260000</AcctSvcrRef>
<BkTxCd/>
<NtryDtls>
<TxDtls>
<BkTxCd>
<Prtry>
<Cd>NMSC+051</Cd>
<Issr>ZKA</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Testkonto Nummer 2</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<Othr>
<Id> 740618130100033626</Id>
<SchmeNm>
<Cd>BBAN</Cd>
</SchmeNm>
</Othr>
</Id>
</DbtrAcct>
</RltdPties>
<RmtInf>
<Ustrd>R CKBUCHUNG</Ustrd>
</RmtInf>
</TxDtls>
</NtryDtls>
</Ntry>
<Ntry>
<Amt Ccy="EUR">6.00</Amt>
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-12-27</Dt>
</BookgDt>
<ValDt>
<Dt>2013-12-27</Dt>
</ValDt>
<AcctSvcrRef>2013122711513230000</AcctSvcrRef>
<BkTxCd/>
<NtryDtls>
<Btch>
<PmtInfId>STZV-PmInf27122013-11:02-2</PmtInfId>
<NbOfTxs>2</NbOfTxs>
</Btch>
<TxDtls>
<Refs>
<MsgId>STZV-Msg27122013-11:02</MsgId>
<EndToEndId>STZV-EtE27122013-11:02-1</EndToEndId>
</Refs>
<AmtDtls>
<TxAmt>
<Amt Ccy="EUR">3.50</Amt>
</TxAmt>
</AmtDtls>
<BkTxCd>
<Prtry>
<Cd>NMSC+201</Cd>
<Issr>ZKA</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Testkonto Nummer 2</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>DE58740618130100033626</IBAN>
</Id>
</DbtrAcct>
<UltmtDbtr>
<Nm>keine Information vorhanden</Nm>
</UltmtDbtr>
<Cdtr>
<Nm>Testkonto Nummer 1</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE14740618130000033626</IBAN>
</Id>
</CdtrAcct>
<UltmtCdtr>
<Nm>Testkonto</Nm>
</UltmtCdtr>
</RltdPties>
<RmtInf>
<Ustrd>Sammelueberwseisung 2. Zahlung TAN:283044 </Ustrd>
</RmtInf>
</TxDtls>
<TxDtls>
<Refs>
<MsgId>STZV-Msg27122013-11:02</MsgId>
<EndToEndId>STZV-EtE27122013-11:02-2</EndToEndId>
</Refs>
<AmtDtls>
<TxAmt>
<Amt Ccy="EUR">2.50</Amt>
</TxAmt>
</AmtDtls>
<BkTxCd>
<Prtry>
<Cd>NMSC+201</Cd>
<Issr>ZKA</Issr>
</Prtry>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Testkonto Nummer 2</Nm>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>DE58740618130100033626</IBAN>
</Id>
</DbtrAcct>
<UltmtDbtr>
<Nm>keine Information vorhanden</Nm>
</UltmtDbtr>
<Cdtr>
<Nm>Testkonto Nummer 1</Nm>
</Cdtr>
<CdtrAcct>
<Id>
<IBAN>DE14740618130000033626</IBAN>
</Id>
</CdtrAcct>
<UltmtCdtr>
<Nm>Testkonto</Nm>
</UltmtCdtr>
</RltdPties>
<RmtInf>
<Ustrd>Sammelueberweisung 1. Zahlung TAN:283044 </Ustrd>
</RmtInf>
</TxDtls>
</NtryDtls>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>

View File

@@ -1,146 +0,0 @@
#
# This file is part of pretix (Community Edition).
#
# Copyright (C) 2014-2020 Raphael Michel and contributors
# Copyright (C) 2020-today pretix GmbH and contributors
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
# Public License as published by the Free Software Foundation in version 3 of the License.
#
# ADDITIONAL TERMS APPLY: Pursuant to Section 7 of the GNU Affero General Public License, additional terms are
# applicable granting you additional permissions and placing additional restrictions on your usage of this software.
# Please refer to the pretix LICENSE file to obtain the full terms applicable to this work. If you did not receive
# this file, see <https://pretix.eu/about/en/license>.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along with this program. If not, see
# <https://www.gnu.org/licenses/>.
#
import os.path
from django.test import TestCase
from pretix.plugins.banktransfer import camtimport
DATA_DIR = os.path.dirname(__file__)
class CamtImportTest(TestCase):
def _test_from_sample_file(self, filename, expected_parsed):
with open(os.path.join(DATA_DIR, filename), "rb") as f:
parsed = camtimport.parse(f)
print(parsed)
self.assertEqual(parsed, expected_parsed)
def test_sample_file_sepatools(self):
expected_parsed = [
{
"amount": "-2.00",
"date": "2013-12-27",
"reference": "TEST BERWEISUNG MITTELS BLZUND KONTONUMMER - DTA",
"external_id": "2013122710583450000",
"payer": "Testkonto Nummer 2",
},
{
"amount": "-3.00",
"date": "2013-12-27",
"reference": "Test+berweisung mit BIC und IBAN SEPA IBAN: DE58740618130100033626 BIC: GENODEF1PFK",
"external_id": "2013122710583600000",
"iban": "DE58740618130100033626",
"payer": "Testkonto Nummer 2",
},
{
"amount": "1.00",
"date": "2013-12-27",
"reference": "R CKBUCHUNG",
"external_id": "2013122711085260000",
"payer": "Testkonto Nummer 2",
},
{
"amount": "-6.00",
"date": "2013-12-27",
"reference": "STZV-PmInf27122013-11:02-2",
"external_id": "2013122711513230000",
},
]
filename = "camt.053_sepatools.xml"
self._test_from_sample_file(filename, expected_parsed)
def test_sample_file_bundesbank(self):
expected_parsed = [
{
"amount": "100000.00",
"date": "2024-03-13",
"reference": "",
"external_id": "103600002791/0019200002",
},
{
"amount": "-25000.00",
"date": "2024-03-13",
"reference": "",
"external_id": "049000039704/0019000002",
},
{
"amount": "-20000.00",
"date": "2024-03-13",
"reference": "",
"external_id": "047200003598/0002000001",
"iban": "DE98200000000020002633",
},
{
"amount": "-15.00",
"date": "2024-03-13",
"reference": "",
"external_id": "047200003598/0002000001",
},
{
"amount": "145015.00",
"date": "2024-03-13",
"reference": "",
"external_id": "051500000059/0019000003",
},
{
"amount": "50000.00",
"date": "2024-03-13",
"reference": "VWZ pacs008 RTGS nach DOTA",
"external_id": "105600004525/0019200003",
},
{
"amount": "80000.00",
"date": "2024-03-13",
"reference": "VWZ pacs009 RTGS nach DOTA",
"external_id": "051800000156/0019000004",
},
{
"amount": "-30000.00",
"date": "2024-03-13",
"reference": "VWZ pacs009 DOTA nach MCA",
"external_id": "055100000086/0019000005",
},
{
"amount": "-120000.00",
"date": "2024-03-13",
"reference": "VWZ pacs009 DOTA nach RTGS",
"external_id": "001400001221/0019000006",
},
{
"amount": "100000.00",
"date": "2024-03-13",
"reference": "",
"external_id": "016900004681/0002000002",
"iban": "DE98200000000020002633",
},
{
"amount": "-280000.00",
"date": "2024-03-13",
"reference": "VWZ pacs008 DOTA nach RTGS",
"external_id": "010300005153/0019000007",
"iban": "DE00IBANbeiTestbank",
},
]
filename = "camt.053_bundesbank.xml"
self._test_from_sample_file(filename, expected_parsed)

View File

@@ -1428,6 +1428,27 @@ class CartTest(CartTestMixin, TestCase):
self.assertEqual(cp2.expires, now() + self.cart_reservation_time)
self.assertEqual(cp2.max_extend, now() + 11 * self.cart_reservation_time)
def test_expired_cart_extend_price_change_note(self):
start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
max_extend = start_time + 11 * self.cart_reservation_time
with scopes_disabled():
cp1 = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=max_extend, max_extend=max_extend
)
cp1.update_listed_price_and_voucher()
self.ticket.default_price = Decimal("25.00")
self.ticket.save()
with freezegun.freeze_time(max_extend + timedelta(hours=1)):
response = self.client.post('/%s/%s/cart/extend' % (self.orga.slug, self.event.slug), {
}, follow=True)
doc = BeautifulSoup(response.rendered_content, "lxml")
self.assertIn('some of the prices in your cart changed', doc.select('.alert-success')[0].text)
with scopes_disabled():
cp1.refresh_from_db()
self.assertEqual(cp1.price, Decimal("25.00"))
self.assertEqual(cp1.expires, now() + self.cart_reservation_time)
def test_expired_cart_extend_fails_partially_on_bundled(self):
start_time = datetime.datetime(2024, 1, 1, 10, 00, 00, tzinfo=datetime.timezone.utc)
max_extend = start_time + 11 * self.cart_reservation_time
@@ -3408,6 +3429,22 @@ class CartAddonTest(CartTestMixin, TestCase):
assert cp2.expires > now()
assert cp2.addon_to_id == cp1.pk
@classscope(attr='orga')
def test_expand_expired_price_change(self):
cp1 = CartPosition.objects.create(
expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time,
item=self.ticket, price=Decimal('23.00'),
event=self.event, cart_id=self.session_key
)
self.ticket.default_price = Decimal("25.00")
self.ticket.save()
self.cm.extend_expired_positions()
self.cm.commit()
cp1.refresh_from_db()
assert cp1.expires > now()
assert cp1.listed_price == Decimal("25.00")
assert cp1.price == Decimal("25.00")
@classscope(attr='orga')
def test_expand_expired_refresh_voucher(self):
v = Voucher.objects.create(item=self.ticket, value=Decimal('20.00'), event=self.event, price_mode='set',
@@ -4080,6 +4117,8 @@ class CartBundleTest(CartTestMixin, TestCase):
@classscope(attr='orga')
def test_extend_bundled_and_addon(self):
self.trans.require_bundling = False
self.trans.save()
cp = CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=21.5, expires=now() - timedelta(minutes=10), max_extend=now() + 10 * self.cart_reservation_time

View File

@@ -2669,7 +2669,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
cr1 = CartPosition.objects.create(
@@ -2839,8 +2839,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
with scopes_disabled():
self.event.has_subevents = True
self.event.save()
se = self.event.subevents.create(name='Foo', date_from=now())
se2 = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
self.quota_tickets.size = 0
self.quota_tickets.subevent = se2
self.quota_tickets.save()
@@ -2880,7 +2880,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24)
@@ -2901,7 +2901,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24, disabled=True)
@@ -2919,7 +2919,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.workshop2)
q.variations.add(self.workshop2b)
@@ -2938,7 +2938,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
SubEventItem.objects.create(subevent=se, item=self.ticket, price=24, available_until=now() - timedelta(days=1))
@@ -2956,7 +2956,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.workshop2)
q.variations.add(self.workshop2b)
@@ -3735,8 +3735,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now())
se2 = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
se2 = self.event.subevents.create(name='Foo', date_from=now(), active=True)
self.quota_tickets.size = 10
self.quota_tickets.subevent = se2
self.quota_tickets.save()
@@ -4165,7 +4165,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
with scopes_disabled():
self.event.has_subevents = True
self.event.save()
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
self.workshopquota.size = 1
self.workshopquota.subevent = se
self.workshopquota.save()
@@ -4214,7 +4214,10 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.settings.display_net_prices = True
self.event.save()
se = self.event.subevents.create(name='Foo', date_from=now(), presale_start=now() + datetime.timedelta(days=1))
se = self.event.subevents.create(name='Foo', date_from=now(), presale_start=now() + datetime.timedelta(days=1),
active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10), subevent=se
@@ -4224,7 +4227,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
assert 'booking period for one of the events in your cart has not yet started.' in response.content.decode()
assert 'booking period for this event has not yet started.' in response.content.decode()
with scopes_disabled():
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
@@ -4233,7 +4236,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.has_subevents = True
self.event.settings.display_net_prices = True
self.event.save()
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() - datetime.timedelta(days=1))
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() - datetime.timedelta(days=1), active=True)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10), subevent=se
@@ -4243,7 +4246,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
assert 'booking period for one of the events in your cart has ended.' in response.content.decode()
assert 'The booking period for this event has ended.' in response.content.decode()
with scopes_disabled():
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
@@ -4253,7 +4256,9 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.settings.display_net_prices = True
self.event.save()
self.event.settings.payment_term_last = 'RELDATE/1/23:59:59/date_from/'
se = self.event.subevents.create(name='Foo', date_from=now())
se = self.event.subevents.create(name='Foo', date_from=now(), active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10), subevent=se
@@ -4263,7 +4268,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
assert 'booking period for one of the events in your cart has ended.' in response.content.decode()
assert 'All payments for this event need to be confirmed already, so no new orders can be created.' in response.content.decode()
with scopes_disabled():
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
@@ -4272,7 +4277,10 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.event.date_to = now() - datetime.timedelta(days=1)
self.event.save()
with scopes_disabled():
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() + datetime.timedelta(days=1))
se = self.event.subevents.create(name='Foo', date_from=now(), presale_end=now() + datetime.timedelta(days=1),
active=True)
q = se.quotas.create(name="foo", size=None, event=self.event)
q.items.add(self.ticket)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10), subevent=se
@@ -4283,6 +4291,25 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertEqual(len(doc.select(".thank-you")), 1)
def test_confirm_subevent_disabled(self):
with scopes_disabled():
self.event.has_subevents = True
self.event.settings.display_net_prices = True
self.event.save()
se = self.event.subevents.create(name='Foo', date_from=now(), active=False)
CartPosition.objects.create(
event=self.event, cart_id=self.session_key, item=self.ticket,
price=23, expires=now() + timedelta(minutes=10), subevent=se
)
self._set_payment()
response = self.client.post('/%s/%s/checkout/confirm/' % (self.orga.slug, self.event.slug), follow=True)
doc = BeautifulSoup(response.content.decode(), "lxml")
self.assertGreaterEqual(len(doc.select(".alert-danger")), 1)
assert 'selected event date is not active.' in response.content.decode()
with scopes_disabled():
assert not CartPosition.objects.filter(cart_id=self.session_key).exists()
def test_before_presale_timemachine(self):
self._login_with_permission(self.orga)
self._enable_test_mode()
@@ -4497,6 +4524,8 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
self.assertEqual(Order.objects.first().locale, 'de')
def test_variation_require_approval(self):
self.workshop2.category = None
self.workshop2.save()
self.workshop2a.require_approval = True
self.workshop2a.save()
with scopes_disabled():
@@ -4518,6 +4547,7 @@ class CheckoutTestCase(BaseCheckoutTestCase, TimemachineTestMixin, TestCase):
def test_item_with_variations_require_approval(self):
self.workshop2.require_approval = True
self.workshop2.category = None
self.workshop2.save()
with scopes_disabled():
cr1 = CartPosition.objects.create(