Compare commits

...

48 Commits

Author SHA1 Message Date
luelista
d6b2e109cf Only set vat_id_validated if vat_id non-empty 2026-05-22 14:40:39 +02:00
Richard Schreiber
909ce5b27d Add NoUrlValidator to validators (#6208) 2026-05-22 13:51:28 +02:00
Raphael Michel
c7b82fdc97 Subevent update: Save SubEvent model before saving plugin forms (#6209) 2026-05-22 13:22:04 +02:00
pajowu
da380ed75e Show invoice_dirty status on order details page (Z#23230731) (#6174) 2026-05-22 10:25:30 +02:00
George Hickman
687c7e3ccf Pin node version to 24 with .node-version (#6207) 2026-05-22 09:34:30 +02:00
robbi5
484b7141d9 Show device name on order print log (#6198) 2026-05-22 09:02:59 +02:00
Richard Schreiber
f60031d67b Make disable_url optional for notifications (#6202) 2026-05-22 07:59:56 +02:00
pajowu
dd29063a84 banktransfer import: Fix prefix confusion if shorter event name contains dash (Z#23234167) (#6189)
Co-authored-by: luelista <weller@rami.io>
2026-05-21 13:03:30 +02:00
Phumraphee Sae-tang
f37dfbd21a Translations: Update Thai
Currently translated at 100.0% (256 of 256 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/th/

powered by weblate
2026-05-21 10:59:46 +02:00
Phumraphee Sae-tang
bb8ef00d49 Translations: Update Thai
Currently translated at 36.4% (2297 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/th/

powered by weblate
2026-05-21 10:59:46 +02:00
Nikolai
d13c654596 Translations: Update Danish
Currently translated at 60.7% (3825 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-05-21 10:59:46 +02:00
Khalid Shaheen
2cc73baa99 Translations: Update Arabic
Currently translated at 58.3% (3673 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ar/

powered by weblate
2026-05-21 10:59:46 +02:00
Richard Schreiber
f740d46d47 Add template-filter human_readable_locale (#6193) 2026-05-20 12:57:57 +02:00
Martin Gross
412a5adf8f Control: Fix typo in gateSelectURL 2026-05-19 22:03:35 +02:00
dependabot[bot]
e4da2e5e03 Update reportlab requirement from ==4.4.* to ==4.5.* (#6138)
Updates the requirements on [reportlab](https://www.reportlab.com/) to permit the latest version.

---
updated-dependencies:
- dependency-name: reportlab
  dependency-version: 4.5.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 18:03:32 +02:00
Richard Schreiber
9d7038b127 Force async_task_is_download to be downloaded if in iframe (Z#23234427) (#6194)
* Force async_task_is_download to be downloaded if in iframe (Z#23234427)

* Update src/pretix/static/pretixbase/js/asynctask.js

Co-authored-by: luelista <weller@rami.io>

---------

Co-authored-by: luelista <weller@rami.io>
2026-05-19 17:07:54 +02:00
Richard Schreiber
ce5af572cc Improve error messages for name-parts inputs (Z#23234440) (#6187)
* Improve error messages for name-parts inputs (Z#23234440)

* fix isort after flake8

* correct spelling of .med in user-provided title/name

* fix search instead of match
2026-05-19 15:23:30 +02:00
dependabot[bot]
6d293e544e Bump django-formtools from 2.5.1 to 2.6.1 (#6191)
Bumps [django-formtools](https://github.com/jazzband/django-formtools) from 2.5.1 to 2.6.1.
- [Changelog](https://github.com/jazzband/django-formtools/blob/master/docs/changelog.rst)
- [Commits](https://github.com/jazzband/django-formtools/compare/2.5.1...2.6.1)

---
updated-dependencies:
- dependency-name: django-formtools
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 11:36:49 +02:00
dependabot[bot]
28a8032adf Update sentry-sdk requirement from ==2.59.* to ==2.60.* (#6190)
Updates the requirements on [sentry-sdk](https://github.com/getsentry/sentry-python) to permit the latest version.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.59.0a1...2.60.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.60.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-19 11:36:25 +02:00
dependabot[bot]
d765a89139 Update djangorestframework requirement from ==3.16.* to ==3.17.* (#6013)
* Update djangorestframework requirement from ==3.16.* to ==3.17.*

Updates the requirements on [djangorestframework](https://github.com/encode/django-rest-framework) to permit the latest version.
- [Release notes](https://github.com/encode/django-rest-framework/releases)
- [Commits](https://github.com/encode/django-rest-framework/compare/3.16.0...3.17.0)

---
updated-dependencies:
- dependency-name: djangorestframework
  dependency-version: 3.17.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>

* Fix failing test

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Raphael Michel <michel@rami.io>
2026-05-18 17:58:43 +02:00
Richard Schreiber
3df5b1d075 Add cssclass for footer-nav and improve button-style in footer (#6167) 2026-05-18 13:16:50 +02:00
Martin Gross
857791445f Docs: Add Exhibitor API docs (Z#23225216) (#6184)
* Docs: Add Exhibitor API docs

* Docs: Add Resource-table for Exhibitor vouchers
2026-05-18 12:02:27 +02:00
dependabot[bot]
52b28997a2 Update fakeredis requirement from ==2.34.* to ==2.35.* (#6072)
* Update fakeredis requirement from ==2.34.* to ==2.35.*

Updates the requirements on [fakeredis](https://github.com/cunla/fakeredis-py) to permit the latest version.
- [Release notes](https://github.com/cunla/fakeredis-py/releases)
- [Commits](https://github.com/cunla/fakeredis-py/compare/v2.34.0...v2.35.0)

---
updated-dependencies:
- dependency-name: fakeredis
  dependency-version: 2.35.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>

* Update class name

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Raphael Michel <michel@rami.io>
2026-05-18 09:48:51 +02:00
dependabot[bot]
f65a6aa11f Update cryptography requirement from >=47.0.0 to >=48.0.0 (#6177)
Updates the requirements on [cryptography](https://github.com/pyca/cryptography) to permit the latest version.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/47.0.0...48.0.0)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 48.0.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-17 16:39:18 +02:00
dependabot[bot]
9faca5ea24 Update sentry-sdk requirement from ==2.58.* to ==2.59.*
Updates the requirements on [sentry-sdk](https://github.com/getsentry/sentry-python) to permit the latest version.
- [Release notes](https://github.com/getsentry/sentry-python/releases)
- [Changelog](https://github.com/getsentry/sentry-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/getsentry/sentry-python/compare/2.58.0a1...2.59.0)

---
updated-dependencies:
- dependency-name: sentry-sdk
  dependency-version: 2.59.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:36:35 +02:00
dependabot[bot]
867512eee5 Bump picomatch
Bumps  and [picomatch](https://github.com/micromatch/picomatch). These dependencies needed to be updated together.

Updates `picomatch` from 4.0.3 to 4.0.4
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

Updates `picomatch` from 2.3.1 to 2.3.2
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/4.0.3...4.0.4)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 4.0.4
  dependency-type: indirect
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:34:46 +02:00
Raphael Michel
1436b65347 Add webhooks for quota changes (Z#23232443) 2026-05-17 16:33:20 +02:00
sweenu
cc06588991 Rephrase refund info paragraph 2026-05-17 16:33:15 +02:00
dependabot[bot]
32bd9fa265 Bump vite from 8.0.0 to 8.0.12
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.0 to 8.0.12.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.0.12/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 8.0.12
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:32:56 +02:00
dependabot[bot]
bdc9b155f9 Bump flatted from 3.3.3 to 3.4.2
Bumps [flatted](https://github.com/WebReflection/flatted) from 3.3.3 to 3.4.2.
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

---
updated-dependencies:
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:32:49 +02:00
dependabot[bot]
1af2941594 Bump postcss from 8.5.8 to 8.5.14
Bumps [postcss](https://github.com/postcss/postcss) from 8.5.8 to 8.5.14.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.8...8.5.14)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:32:45 +02:00
dependabot[bot]
11dc1e6f70 Bump arabic-reshaper from 3.0.0 to 3.0.1
Bumps [arabic-reshaper](https://github.com/mpcabd/python-arabic-reshaper) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/mpcabd/python-arabic-reshaper/releases)
- [Commits](https://github.com/mpcabd/python-arabic-reshaper/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: arabic-reshaper
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-17 16:17:45 +02:00
Nikolai
e08243e3b2 Translations: Update Danish
Currently translated at 59.1% (3725 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/da/

powered by weblate
2026-05-17 15:33:11 +02:00
Yasunobu YesNo Kawaguchi
3a4e30f2ec Translations: Update Japanese
Currently translated at 100.0% (256 of 256 strings)

Translation: pretix/pretix (JavaScript parts)
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix-js/ja/

powered by weblate
2026-05-17 15:33:11 +02:00
Yasunobu YesNo Kawaguchi
ea2fa741f5 Translations: Update Japanese
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-05-17 15:33:11 +02:00
Stefano Campus
20d1bb9d32 Translations: Update Italian
Currently translated at 40.0% (2521 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/it/

powered by weblate
2026-05-17 15:33:11 +02:00
Hijiri Umemoto
ad48d592e7 Translations: Update Japanese
Currently translated at 100.0% (6295 of 6295 strings)

Translation: pretix/pretix
Translate-URL: https://translate.pretix.eu/projects/pretix/pretix/ja/

powered by weblate
2026-05-17 15:33:11 +02:00
pajowu
4861aca640 Fix timepicker in checkinrules (#6182)
The timepickers format was changed by accident to the datetimeformat in the vue3 migration
2026-05-12 16:17:24 +02:00
pajowu
82450c8250 Handle related fields in export_form_data (Z#23233538) (#6157) 2026-05-12 14:55:25 +02:00
Richard Schreiber
b21b69b2b8 Fix playwright install on CI (#6180) 2026-05-12 13:14:05 +02:00
luelista
80ed6e76cd Fix failing orderlist export if orders with invalid payment provider identifiers exist (Z#23233440) (#6159)
* Fix orderlist export if orders with invalid payment provider identifiers exist (Z#23233440)
* Performance: Move _get_all_payment_methods out of loop
2026-05-12 11:57:18 +02:00
Lukas Bockstaller
bb211be436 use datetime.fromisoformat instead of dateutil.parser (Z#23234093) (#6164)
* use datetime.fromisoformat instead of dateutil.parser

* convert remaining parser usages as well
2026-05-12 10:41:24 +02:00
Richard Schreiber
3b70ef8c84 Allow event being optional in LoggingMixin (#6166) 2026-05-12 09:45:42 +02:00
Richard Schreiber
9d57380c9a Widget: fix missing whitespace in PriceBox 2026-05-12 09:34:17 +02:00
Richard Schreiber
8b468c31a5 Fix translation for order import (#6165) 2026-05-12 09:03:34 +02:00
Richard Schreiber
9aec608601 Fix checkinrules js errors 2026-05-12 08:34:22 +02:00
Raphael Michel
e542bb606d Vue3: Minor fixes in checkinlist editor 2026-05-11 18:51:21 +02:00
Raphael Michel
fe1b4ec9d0 Order bulk action: Remove nonsensical <form action> attribute (#6154) 2026-05-11 17:39:46 +02:00
49 changed files with 1082 additions and 723 deletions

View File

@@ -123,7 +123,7 @@ jobs:
working-directory: ./src
run: make all compress
- name: Install Playwright browsers
run: npx playwright install
run: playwright install
- name: Run E2E tests
working-directory: ./src
run: PRETIX_CONFIG_FILE=tests/ci_postgres.cfg py.test tests/e2e/ -v --maxfail=10

View File

@@ -1 +1 @@
17
24

View File

@@ -844,3 +844,187 @@ You can also fetch existing leads (if you are authorized to do so):
:statuscode 200: No error
:statuscode 401: Invalid authentication code
:statuscode 403: Not permitted to access bulk data
Retrieving Vouchers
"""""""""""""""""""
Vouchers returned by the App API use a different format than described in :ref:`rest-vouchers`.
.. rst-class:: rest-resource-table
===================================== ========================== =======================================================
Field Type Description
===================================== ========================== =======================================================
id integer Internal ID of the voucher
code string The voucher code that is required to redeem the voucher
max_usages integer The maximum number of times this voucher can be
redeemed (default: 1).
redeemed integer The number of times this voucher already has been
redeemed.
valid_until datetime The voucher expiration date (or ``null``).
subevent string Name of the date inside an event series this voucher belongs to (or ``null``).
tag string A string that is used for grouping vouchers
comment string An internal exhibitor comment on the voucher.
items list of strings A list of items this voucher is restricted to (or ``null``).
price_mode string Determines how this voucher affects product prices.
Possible values:
* ``none`` No effect on price
* ``set`` The product price is set to the given ``value``
* ``subtract`` The product price is determined by the original price *minus* the given ``value``
* ``percent`` The product price is determined by the original price reduced by the percentage given in ``value``
value decimal (string) The value (see ``price_mode``)
redemptions list of objects A list of objects, where each object represents an order position that has been purchased using the voucher.
Each entry will contains the fields ``attendee_fields``, ``redemption_date`` and ``subevent``.
The attendee data in the ``attendee_fields`` that is shown is based on the event's configuration, and each entry
contains the fields ``id``, ``label``, ``value``, and ``details``. ``details`` is usually empty
except in a few cases where it contains an additional list of objects
with ``value`` and ``label`` keys (e.g. splitting of names).
===================================== ========================== =======================================================
.. http:get:: /exhibitors/api/v1/vouchers/
Returns a list of all vouchers connected to the exhibitor.
Note that the ``attendee_fields`` array can contain any number of dynamic keys!
Depending on the exhibitors permission and event configuration this might be empty, or contain lots of details.
The app should dynamically show these values (read-only) with the labels sent by the server.
**Example request**:
.. sourcecode:: http
GET /exhibitors/api/v1/vouchers/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"code": "43K6LKM37FBVR2YG",
"max_usages": 1,
"redeemed": 0,
"valid_until": null,
"subevent": null,
"tag": "testvoucher",
"comment": "",
"items": [
"All"
],
"price_mode": "set",
"value": "12.00",
"redemptions": [
{
"attendee_fields": [
{
"id": "attendee_name",
"label": "Name",
"value": "Jon Doe",
"details": [
{"label": "Given name", "value": "John"},
{"label": "Family name", "value": "Doe"},
]
},
{
"id": "attendee_email",
"label": "Email",
"value": "test@example.com",
"details": []
}
],
"redemption_date": "2026-05-06",
"subevent": null
},
]
}
]
}
:statuscode 200: No error
:statuscode 401: Invalid authentication code
:statuscode 403: Not permitted to access bulk data
.. http:get:: /exhibitors/api/v1/vouchers/(id)/
Returns the details of a single, specific voucher connected to the exhibitor.
Note that the ``attendee_fields`` array can contain any number of dynamic keys!
Depending on the exhibitors permission and event configuration this might be empty, or contain lots of details.
The app should dynamically show these values (read-only) with the labels sent by the server.
**Example request**:
.. sourcecode:: http
GET /exhibitors/api/v1/vouchers/1/ HTTP/1.1
Host: pretix.eu
Accept: application/json, text/javascript
**Example response**:
.. sourcecode:: http
HTTP/1.1 200 OK
Vary: Accept
Content-Type: application/json
{
"id": 1,
"code": "43K6LKM37FBVR2YG",
"max_usages": 1,
"redeemed": 0,
"valid_until": null,
"subevent": null,
"tag": "testvoucher",
"comment": "",
"items": [
"All"
],
"price_mode": "set",
"value": "12.00",
"redemptions": [
{
"attendee_fields": [
{
"id": "attendee_name",
"label": "Name",
"value": "Jon Doe",
"details": [
{"label": "Given name", "value": "John"},
{"label": "Family name", "value": "Doe"},
]
},
{
"id": "attendee_email",
"label": "Email",
"value": "test@example.com",
"details": []
}
],
"redemption_date": "2026-05-06",
"subevent": null
},
]
}
:param id: The ``id`` field of the voucher to fetch
:statuscode 200: No error
:statuscode 401: Invalid authentication code
:statuscode 403: Not permitted to access bulk data
:statuscode 404: Voucher not found in system

View File

@@ -70,6 +70,7 @@ The following values for ``action_types`` are valid with pretix core:
* ``pretix.subevent.changed``
* ``pretix.subevent.deleted``
* ``pretix.event.item.*``
* ``pretix.event.quota.*``
* ``pretix.event.live.activated``
* ``pretix.event.live.deactivated``
* ``pretix.event.testmode.activated``

247
package-lock.json generated
View File

@@ -93,21 +93,21 @@
"license": "(Apache-2.0 AND BSD-3-Clause)"
},
"node_modules/@emnapi/core": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.0.tgz",
"integrity": "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/wasi-threads": "1.2.0",
"@emnapi/wasi-threads": "1.2.1",
"tslib": "^2.4.0"
}
},
"node_modules/@emnapi/runtime": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.0.tgz",
"integrity": "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw==",
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -116,9 +116,9 @@
}
},
"node_modules/@emnapi/wasi-threads": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.0.tgz",
"integrity": "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg==",
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
"integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -370,20 +370,22 @@
"license": "MIT"
},
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.1.tgz",
"integrity": "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
"integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==",
"dev": true,
"license": "MIT",
"optional": true,
"dependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1",
"@tybys/wasm-util": "^0.10.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/Brooooooklyn"
},
"peerDependencies": {
"@emnapi/core": "^1.7.1",
"@emnapi/runtime": "^1.7.1"
}
},
"node_modules/@nodelib/fs.scandir": {
@@ -424,20 +426,10 @@
"node": ">= 8"
}
},
"node_modules/@oxc-project/runtime": {
"version": "0.115.0",
"resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.115.0.tgz",
"integrity": "sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@oxc-project/types": {
"version": "0.115.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.115.0.tgz",
"integrity": "sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==",
"version": "0.129.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.129.0.tgz",
"integrity": "sha512-3oz8m3FGdr2nDXVqmFUw7jolKliC4MoyXYIG2c7gpjBnzUWQpUGIYcXYKxTdTi+N2jusvt610ckTMkxdwHkYEg==",
"dev": true,
"license": "MIT",
"funding": {
@@ -766,9 +758,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.9.tgz",
"integrity": "sha512-lcJL0bN5hpgJfSIz/8PIf02irmyL43P+j1pTCfbD1DbLkmGRuFIA4DD3B3ZOvGqG0XiVvRznbKtN0COQVaKUTg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0.tgz",
"integrity": "sha512-TWMZnRLMe63C2Lhyicviu7ZHaU4kxa6PS3rofvc9GmcvptzNN11BcfQ4Sl7MwTOsisQoa2keB/EBdNCAnUo8vA==",
"cpu": [
"arm64"
],
@@ -783,9 +775,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.9.tgz",
"integrity": "sha512-J7Zk3kLYFsLtuH6U+F4pS2sYVzac0qkjcO5QxHS7OS7yZu2LRs+IXo+uvJ/mvpyUljDJ3LROZPoQfgBIpCMhdQ==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0.tgz",
"integrity": "sha512-6XcD+8k0gPVItNagEw78/qqcBDwKcwDYS8V2hRmVsfUSIrd8cWe/CBvRDI5toqFyPfj+FJr6t8U6Xj2P2prEew==",
"cpu": [
"arm64"
],
@@ -800,9 +792,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.9.tgz",
"integrity": "sha512-iwtmmghy8nhfRGeNAIltcNXzD0QMNaaA5U/NyZc1Ia4bxrzFByNMDoppoC+hl7cDiUq5/1CnFthpT9n+UtfFyg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0.tgz",
"integrity": "sha512-iN/tWVXRQDWvmZlKdceP1Dwug9GDpEymhb9p4xnEe6zvCg5lFmzVljl+1qR1NVx3yfGpr2Na+CuLmv5IU8uzfQ==",
"cpu": [
"x64"
],
@@ -817,9 +809,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.9.tgz",
"integrity": "sha512-DLFYI78SCiZr5VvdEplsVC2Vx53lnA4/Ga5C65iyldMVaErr86aiqCoNBLl92PXPfDtUYjUh+xFFor40ueNs4Q==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0.tgz",
"integrity": "sha512-jjQMDvvwSOuhOwMszD/klSOjyWMM3zI64hWTj9KT5x4MxRbZAf+7vLQ6qouRhtsLVFHr3f0ILaJAfgENPiQdAQ==",
"cpu": [
"x64"
],
@@ -834,9 +826,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.9.tgz",
"integrity": "sha512-CsjTmTwd0Hri6iTw/DRMK7kOZ7FwAkrO4h8YWKoX/kcj833e4coqo2wzIFywtch/8Eb5enQ/lwLM7w6JX1W5RQ==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0.tgz",
"integrity": "sha512-d//Dtg2x6/m3mbV64yUGNnDGNZaDGRpDLLNGerHQUVObuNaIQaaDp25yUiqGXtHEXX+NP2d0wAlmKgpYgIAJ2A==",
"cpu": [
"arm"
],
@@ -851,9 +843,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.9.tgz",
"integrity": "sha512-2x9O2JbSPxpxMDhP9Z74mahAStibTlrBMW0520+epJH5sac7/LwZW5Bmg/E6CXuEF53JJFW509uP+lSedaUNxg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0.tgz",
"integrity": "sha512-n7Ofp0mx+aB2cC+Sdy5YtMnXtY9lchnHbY+3Yt0uq9JsWQExf4f5Whu0tK0R8Jdc9S6RchTHjIFY7uc92puOVQ==",
"cpu": [
"arm64"
],
@@ -868,9 +860,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.9.tgz",
"integrity": "sha512-JA1QRW31ogheAIRhIg9tjMfsYbglXXYGNPLdPEYrwFxdbkQCAzvpSCSHCDWNl4hTtrol8WeboCSEpjdZK8qrCg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0.tgz",
"integrity": "sha512-EIVjy2cgd7uuMMo94FVkBp7F6DhcZAUwNURkSG3RwUmvAXR6s0ISxM81U+IydcZByPG0pZIHsf1b6kTxoFDgJA==",
"cpu": [
"arm64"
],
@@ -885,9 +877,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.9.tgz",
"integrity": "sha512-aOKU9dJheda8Kj8Y3w9gnt9QFOO+qKPAl8SWd7JPHP+Cu0EuDAE5wokQubLzIDQWg2myXq2XhTpOVS07qqvT+w==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0.tgz",
"integrity": "sha512-JEwwOPcwTLAcpDQlqSmjEmfs63xJnSiUNIGvLcDLUHCWK4XowpS/7c7tUsUH6uT/ct6bMUTdXKfI8967FYj6mg==",
"cpu": [
"ppc64"
],
@@ -902,9 +894,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.9.tgz",
"integrity": "sha512-OalO94fqj7IWRn3VdXWty75jC5dk4C197AWEuMhIpvVv2lw9fiPhud0+bW2ctCxb3YoBZor71QHbY+9/WToadA==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0.tgz",
"integrity": "sha512-0wjCFhLrihtAubnT9iA0N++0pSV0z5Hg7tNGdNJ4RFaINceHadoF+kiFGyY1qSSNVIAZtLotG8Ju1bgDPkjnFA==",
"cpu": [
"s390x"
],
@@ -919,9 +911,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.9.tgz",
"integrity": "sha512-cVEl1vZtBsBZna3YMjGXNvnYYrOJ7RzuWvZU0ffvJUexWkukMaDuGhUXn0rjnV0ptzGVkvc+vW9Yqy6h8YX4pg==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0.tgz",
"integrity": "sha512-Dfn7iak9BcMMePxcoJfpSbWqnEyrp/dRF63/8qW/eHBdOZov6x5aShLLEYGYdIeSJ6vMLK/XCVB+lGIxm41bQA==",
"cpu": [
"x64"
],
@@ -936,9 +928,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.9.tgz",
"integrity": "sha512-UzYnKCIIc4heAKgI4PZ3dfBGUZefGCJ1TPDuLHoCzgrMYPb5Rv6TLFuYtyM4rWyHM7hymNdsg5ik2C+UD9VDbA==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0.tgz",
"integrity": "sha512-5/utzzDmD/pD/bmuaUcbTf/sZYy0aztwIVlfpoW1fTjCZ0BaPOMVWGZL1zvgxyi7ZIVYWlxKONHmSbHuiOh8Jw==",
"cpu": [
"x64"
],
@@ -953,9 +945,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.9.tgz",
"integrity": "sha512-+6zoiF+RRyf5cdlFQP7nm58mq7+/2PFaY2DNQeD4B87N36JzfF/l9mdBkkmTvSYcYPE8tMh/o3cRlsx1ldLfog==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0.tgz",
"integrity": "sha512-ouJs8VcUomfLfpbUECqFMRqdV4x6aeAK3MA4m6vTrJJjKyWTV5KnxZx7Jd9G+GlDaQQxubcba00x16OyJ1meig==",
"cpu": [
"arm64"
],
@@ -970,9 +962,9 @@
}
},
"node_modules/@rolldown/binding-wasm32-wasi": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.9.tgz",
"integrity": "sha512-rgFN6sA/dyebil3YTlL2evvi/M+ivhfnyxec7AccTpRPccno/rPoNlqybEZQBkcbZu8Hy+eqNJCqfBR8P7Pg8g==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0.tgz",
"integrity": "sha512-E+oHKGiDA+lsKMmFtffDDw91EryDT7uJocrIuCHqhm6bCTM6xFK+3gaCkYOHfPwQr0cCNarSM2xaELoQDz9jJg==",
"cpu": [
"wasm32"
],
@@ -980,16 +972,18 @@
"license": "MIT",
"optional": true,
"dependencies": {
"@napi-rs/wasm-runtime": "^1.1.1"
"@emnapi/core": "1.10.0",
"@emnapi/runtime": "1.10.0",
"@napi-rs/wasm-runtime": "^1.1.4"
},
"engines": {
"node": ">=14.0.0"
"node": "^20.19.0 || >=22.12.0"
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.9.tgz",
"integrity": "sha512-lHVNUG/8nlF1IQk1C0Ci574qKYyty2goMiPlRqkC5R+3LkXDkL5Dhx8ytbxq35m+pkHVIvIxviD+TWLdfeuadA==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0.tgz",
"integrity": "sha512-yYK02n8Rngo+gbm1y6G0+7jk1sJ/2Wt7K0me0Y7k/ErBpyf+LJ2gFpqWVTcRV1rUepBlQRmpgWkTQCiiwrK0Ow==",
"cpu": [
"arm64"
],
@@ -1004,9 +998,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.9.tgz",
"integrity": "sha512-G0oA4+w1iY5AGi5HcDTxWsoxF509hrFIPB2rduV5aDqS9FtDg1CAfa7V34qImbjfhIcA8C+RekocJZA96EarwQ==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0.tgz",
"integrity": "sha512-14bpChMahXRRXiTwahSl+zzHPW6qQTXtkMuJBFlbo+pqSAews2d4BdCSHfrJ/MBsCZtpmTafsY+1QhBzitcmdg==",
"cpu": [
"x64"
],
@@ -1049,9 +1043,9 @@
}
},
"node_modules/@tybys/wasm-util": {
"version": "0.10.1",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
"version": "0.10.2",
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz",
"integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==",
"dev": true,
"license": "MIT",
"optional": true,
@@ -2362,9 +2356,9 @@
}
},
"node_modules/flatted": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
"version": "3.4.2",
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
"dev": true,
"license": "ISC"
},
@@ -3111,9 +3105,9 @@
}
},
"node_modules/micromatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3327,9 +3321,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3340,9 +3334,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.8",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz",
"integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==",
"version": "8.5.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz",
"integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==",
"funding": [
{
"type": "opencollective",
@@ -3616,14 +3610,14 @@
}
},
"node_modules/rolldown": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.9.tgz",
"integrity": "sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0.tgz",
"integrity": "sha512-yD986aXDESFGS95spT1LAv0jssywP4npMEjmMHyN2/5+eE8qQJUype2AaKkRiLgBgyD0LFlubwAht7VmY8rGoA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.115.0",
"@rolldown/pluginutils": "1.0.0-rc.9"
"@oxc-project/types": "=0.129.0",
"@rolldown/pluginutils": "1.0.0"
},
"bin": {
"rolldown": "bin/cli.mjs"
@@ -3632,27 +3626,27 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
"@rolldown/binding-android-arm64": "1.0.0-rc.9",
"@rolldown/binding-darwin-arm64": "1.0.0-rc.9",
"@rolldown/binding-darwin-x64": "1.0.0-rc.9",
"@rolldown/binding-freebsd-x64": "1.0.0-rc.9",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.9",
"@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.9",
"@rolldown/binding-linux-arm64-musl": "1.0.0-rc.9",
"@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.9",
"@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.9",
"@rolldown/binding-linux-x64-gnu": "1.0.0-rc.9",
"@rolldown/binding-linux-x64-musl": "1.0.0-rc.9",
"@rolldown/binding-openharmony-arm64": "1.0.0-rc.9",
"@rolldown/binding-wasm32-wasi": "1.0.0-rc.9",
"@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.9",
"@rolldown/binding-win32-x64-msvc": "1.0.0-rc.9"
"@rolldown/binding-android-arm64": "1.0.0",
"@rolldown/binding-darwin-arm64": "1.0.0",
"@rolldown/binding-darwin-x64": "1.0.0",
"@rolldown/binding-freebsd-x64": "1.0.0",
"@rolldown/binding-linux-arm-gnueabihf": "1.0.0",
"@rolldown/binding-linux-arm64-gnu": "1.0.0",
"@rolldown/binding-linux-arm64-musl": "1.0.0",
"@rolldown/binding-linux-ppc64-gnu": "1.0.0",
"@rolldown/binding-linux-s390x-gnu": "1.0.0",
"@rolldown/binding-linux-x64-gnu": "1.0.0",
"@rolldown/binding-linux-x64-musl": "1.0.0",
"@rolldown/binding-openharmony-arm64": "1.0.0",
"@rolldown/binding-wasm32-wasi": "1.0.0",
"@rolldown/binding-win32-arm64-msvc": "1.0.0",
"@rolldown/binding-win32-x64-msvc": "1.0.0"
}
},
"node_modules/rolldown/node_modules/@rolldown/pluginutils": {
"version": "1.0.0-rc.9",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.9.tgz",
"integrity": "sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0.tgz",
"integrity": "sha512-aKs/3GSWyV0mrhNmt/96/Z3yczC3yvrzYATCiCXQebBsGyYzjNdUphRVLeJQ67ySKVXRfMxt2lm12pmXvbPFQQ==",
"dev": true,
"license": "MIT"
},
@@ -4331,14 +4325,14 @@
}
},
"node_modules/tinyglobby": {
"version": "0.2.15",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
"version": "0.2.16",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz",
"integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fdir": "^6.5.0",
"picomatch": "^4.0.3"
"picomatch": "^4.0.4"
},
"engines": {
"node": ">=12.0.0"
@@ -4471,18 +4465,17 @@
"license": "MIT"
},
"node_modules/vite": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.0.tgz",
"integrity": "sha512-fPGaRNj9Zytaf8LEiBhY7Z6ijnFKdzU/+mL8EFBaKr7Vw1/FWcTBAMW0wLPJAGMPX38ZPVCVgLceWiEqeoqL2Q==",
"version": "8.0.12",
"resolved": "https://registry.npmjs.org/vite/-/vite-8.0.12.tgz",
"integrity": "sha512-w2dDofOWv2QB09ZITZBsvKTVAlYvPR4IAmrY/v0ir9KvLs0xybR7i48wxhM1/oyBWO34wPns+bPGw5ZrZqDpZg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@oxc-project/runtime": "0.115.0",
"lightningcss": "^1.32.0",
"picomatch": "^4.0.3",
"postcss": "^8.5.8",
"rolldown": "1.0.0-rc.9",
"tinyglobby": "^0.2.15"
"picomatch": "^4.0.4",
"postcss": "^8.5.14",
"rolldown": "1.0.0",
"tinyglobby": "^0.2.16"
},
"bin": {
"vite": "bin/vite.js"
@@ -4498,8 +4491,8 @@
},
"peerDependencies": {
"@types/node": "^20.19.0 || >=22.12.0",
"@vitejs/devtools": "^0.0.0-alpha.31",
"esbuild": "^0.27.0",
"@vitejs/devtools": "^0.1.18",
"esbuild": "^0.27.0 || ^0.28.0",
"jiti": ">=1.21.0",
"less": "^4.0.0",
"sass": "^1.70.0",

View File

@@ -27,13 +27,13 @@ classifiers = [
]
dependencies = [
"arabic-reshaper==3.0.0", # Support for Arabic in reportlab
"arabic-reshaper==3.0.1", # Support for Arabic in reportlab
"babel",
"BeautifulSoup4==4.14.*",
"bleach==6.3.*",
"celery==5.6.*",
"chardet==5.2.*",
"cryptography>=47.0.0",
"cryptography>=48.0.0",
"css-inline==0.20.*",
"defusedcsv>=3.0.0",
"dnspython==2.*",
@@ -43,7 +43,7 @@ dependencies = [
"django-countries==8.2.*",
"django-filter==25.1",
"django-formset-js-improved==0.5.0.5",
"django-formtools==2.5.1",
"django-formtools==2.6.1",
"django-hierarkey==2.0.*,>=2.0.1",
"django-hijack==3.7.*",
"django-i18nfield==1.11.*",
@@ -56,7 +56,7 @@ dependencies = [
"django-redis==6.0.*",
"django-scopes==2.0.*",
"django-statici18n==2.7.*",
"djangorestframework==3.16.*",
"djangorestframework==3.17.*",
"dnspython==2.8.*",
"drf_ujson2==1.7.*",
"geoip2==5.*",
@@ -91,9 +91,9 @@ dependencies = [
"pyuca",
"qrcode==8.2",
"redis==7.4.*",
"reportlab==4.4.*",
"reportlab==4.5.*",
"requests==2.32.*",
"sentry-sdk==2.58.*",
"sentry-sdk==2.60.*",
"sepaxml==2.7.*",
"stripe==7.9.*",
"text-unidecode==1.*",
@@ -111,7 +111,7 @@ dev = [
"aiohttp==3.13.*",
"coverage",
"coveralls",
"fakeredis==2.34.*",
"fakeredis==2.35.*",
"flake8==7.3.*",
"freezegun",
"isort==8.0.*",
@@ -126,6 +126,7 @@ dev = [
"pytest-xdist==3.8.*",
"pytest-playwright",
"pytest==9.0.*",
"playwright",
"responses",
]

View File

@@ -133,37 +133,43 @@ class JobRunSerializer(serializers.Serializer):
return not bool(self._errors)
class ExportFormDataField(serializers.Field):
def get_attribute(self, instance):
return (instance.export_identifier, instance.export_form_data)
def to_representation(self, value):
export_identifier, export_form_data = value
exporter = self.context['exporters'].get(export_identifier)
if exporter:
return JobRunSerializer(exporter=exporter).to_representation(export_form_data)
else:
return export_form_data
def get_value(self, dictionary):
return dictionary
def to_internal_value(self, data):
if "export_form_data" in data:
identifier = data.get('export_identifier', self.parent.instance.export_identifier if self.parent.instance else None)
exporter = self.context['exporters'].get(identifier)
if exporter:
return JobRunSerializer(exporter=exporter).to_internal_value(data["export_form_data"])
else:
return data['export_form_data']
class ScheduledExportSerializer(serializers.ModelSerializer):
schedule_next_run = serializers.DateTimeField(read_only=True)
export_identifier = serializers.ChoiceField(choices=[])
locale = serializers.ChoiceField(choices=settings.LANGUAGES, default='en')
owner = serializers.SlugRelatedField(slug_field='email', read_only=True)
error_counter = serializers.IntegerField(read_only=True)
export_form_data = ExportFormDataField()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['export_identifier'].choices = [(e, e) for e in self.context['exporters']]
def validate(self, attrs):
if attrs.get("export_form_data"):
identifier = attrs.get('export_identifier', self.instance.export_identifier if self.instance else None)
exporter = self.context['exporters'].get(identifier)
if exporter:
try:
attrs["export_form_data"] = JobRunSerializer(exporter=exporter).to_internal_value(attrs["export_form_data"])
except ValidationError as e:
raise ValidationError({"export_form_data": e.detail})
else:
raise ValidationError({"export_identifier": ["Unknown exporter."]})
return attrs
def to_representation(self, instance):
repr = super().to_representation(instance)
exporter = self.context['exporters'].get(instance.export_identifier)
if exporter:
repr["export_form_data"] = JobRunSerializer(exporter=exporter).to_representation(repr["export_form_data"])
return repr
def validate_mail_additional_recipients(self, value):
d = value.replace(' ', '')
if len(d.split(',')) > 25:

View File

@@ -45,6 +45,12 @@ class PrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
return value
return super().to_representation(value)
def to_internal_value(self, data):
value = super().to_internal_value(data)
if value is not None:
return value.pk
return value
class FormFieldWrapperField(serializers.Field):
def __init__(self, *args, **kwargs):

View File

@@ -408,6 +408,12 @@ def register_default_webhook_events(sender, **kwargs):
_('This includes product added or deleted and changes to nested objects like '
'variations or bundles.'),
),
ParametrizedItemWebhookEvent(
'pretix.event.quota.*',
_('Quota changed'),
_('This includes related events like creation, deletion, opening or closing of quotas. '
'No webhook is sent for changes to the resulting availability.'),
),
ParametrizedEventWebhookEvent(
'pretix.event.live.activated',
_('Shop taken live'),

View File

@@ -160,7 +160,7 @@ class OrderListExporter(MultiSheetListExporter):
def _get_all_payment_methods(self, qs):
pps = dict(get_all_payment_providers())
return sorted([(pp, pps[pp]) for pp in set(
return sorted([(pp, pps.get(pp, pp)) for pp in set(
OrderPayment.objects.exclude(provider='free').filter(order__event__in=self.events).values_list(
'provider', flat=True
).distinct()
@@ -330,6 +330,7 @@ class OrderListExporter(MultiSheetListExporter):
taxsum=Sum('tax_value'), grosssum=Sum('value')
)
}
payment_methods = None
if form_data.get('include_payment_amounts'):
payment_sum_cache = {
(o['order__id'], o['provider']): o['grosssum'] for o in
@@ -347,6 +348,7 @@ class OrderListExporter(MultiSheetListExporter):
grosssum=Sum('amount')
)
}
payment_methods = self._get_all_payment_methods(qs)
sum_cache = {
(o['order__id'], o['tax_rate']): o for o in
OrderPosition.objects.values('tax_rate', 'order__id').order_by().annotate(
@@ -434,7 +436,6 @@ class OrderListExporter(MultiSheetListExporter):
)
if form_data.get('include_payment_amounts'):
payment_methods = self._get_all_payment_methods(qs)
for id, vn in payment_methods:
row.append(
payment_sum_cache.get((order.id, id), Decimal('0.00')) -

View File

@@ -35,6 +35,7 @@
import copy
import json
import logging
import re
from datetime import timedelta
from decimal import Decimal
from io import BytesIO
@@ -47,9 +48,7 @@ from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.validators import (
MaxValueValidator, MinValueValidator, RegexValidator,
)
from django.core.validators import MaxValueValidator, MinValueValidator
from django.db.models import QuerySet
from django.forms import Select, widgets
from django.forms.widgets import FILE_INPUT_CONTRADICTION
@@ -220,20 +219,6 @@ class NamePartsFormField(forms.MultiValueField):
defaults = {
'widget': self.widget,
'max_length': kwargs.pop('max_length', None),
'validators': [
RegexValidator(
# The following characters should never appear in a name anywhere of
# the world. However, they commonly appear in inputs generated by spam
# bots.
r'^[^$€/%§{}<>~]*$',
message=_('Please do not use special characters in names.')
),
RegexValidator(
URL_RE,
inverse_match=True,
message=_('Please do not use special characters in names.')
)
]
}
self.max_length = defaults['max_length']
self.scheme_name = kwargs.pop('scheme')
@@ -255,7 +240,6 @@ class NamePartsFormField(forms.MultiValueField):
if fname == 'title' and self.scheme_titles:
d = dict(defaults)
d.pop('max_length', None)
d.pop('validators', None)
field = forms.ChoiceField(
**d,
choices=[('', '')] + [(d, d) for d in self.scheme_titles[1]]
@@ -264,7 +248,6 @@ class NamePartsFormField(forms.MultiValueField):
elif fname == 'salutation':
d = dict(defaults)
d.pop('max_length', None)
d.pop('validators', None)
field = forms.ChoiceField(
**d,
choices=[
@@ -296,6 +279,37 @@ class NamePartsFormField(forms.MultiValueField):
if sum(len(v) for v in value.values() if v) > (self.max_length or 250):
raise forms.ValidationError(_('Please enter a shorter name.'), code='max_length')
for fname, label, size in self.scheme['fields']:
if fname == 'salutation' or (fname == 'title' and self.scheme_titles):
continue
v = value.get(fname)
if not v:
continue
special_chars = re.findall('[$€/%§{}<>~]', v)
if special_chars:
raise forms.ValidationError(
_('The field "%(label)s" may not contain special characters such as "%(chars)s".'),
code='name_special_chars',
params={
"label": label,
"chars": "".join(special_chars),
},
)
# URL_RE checks for valid domain names, including one special TLD med, which can be part of a title
if ".med" in v:
v = v.replace(".med", ". med")
value[fname] = v
url_matched = URL_RE.search(v)
if url_matched:
raise forms.ValidationError(
_('The field "%(label)s" may not contain an URL (%(url)s).'),
code='url_in_title',
params={
"label": label,
"url": url_matched.group(0),
}
)
if value.get("salutation") == "empty":
value["salutation"] = ""
@@ -1384,7 +1398,7 @@ class BaseInvoiceAddressForm(forms.ModelForm):
elif self.validate_vat_id and vat_id_applicable:
try:
normalized_id = validate_vat_id(data.get('vat_id'), str(data.get('country')))
self.instance.vat_id_validated = True
self.instance.vat_id_validated = bool(normalized_id)
self.instance.vat_id = data['vat_id'] = normalized_id
except VATIDFinalError as e:
if self.all_optional:

View File

@@ -442,7 +442,7 @@ class AttendeeState(ImportColumn):
@property
def verbose_name(self):
return _('Attendee address') + ': ' + _('State')
return _('Attendee address') + ': ' + pgettext('address', 'State')
def clean(self, value, previous_values):
if value:

View File

@@ -125,7 +125,7 @@ class LoggingMixin:
elif isinstance(self, Event):
event = self
organizer_id = self.organizer_id
elif hasattr(self, 'event'):
elif hasattr(self, 'event') and self.event:
event = self.event
organizer_id = self.event.organizer_id
elif hasattr(self, 'organizer_id'):

View File

@@ -55,10 +55,12 @@
{% trans "You receive these emails based on your notification settings." %}<br>
<a href="{{ settings_url }}">
{% trans "Click here to view and change your notification settings" %}
</a><br>
<a href="{{ disable_url }}">
{% trans "Click here disable all notifications immediately." %}
</a>
{% if disable_url %}<br>
<a href="{{ disable_url }}">
{% trans "Click here disable all notifications immediately." %}
</a>
{% endif %}
</div>
<!--[if gte mso 9]>
</td></tr></table>

View File

@@ -14,5 +14,6 @@
{% trans "You receive these emails based on your notification settings." %}
{% trans "Click here to view and change your notification settings:" %}
{{ settings_url }}
{% trans "Click here disable all notifications immediately:" %}
{% if disable_url %}{% trans "Click here disable all notifications immediately:" %}
{{ disable_url }}
{% endif %}

View File

@@ -0,0 +1,32 @@
#
# 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 import template
from django.conf import settings
register = template.Library()
@register.filter
def human_readable_locale(value):
if not value:
return ''
return dict(settings.LANGUAGES).get(value, '')

View File

@@ -24,10 +24,12 @@ import calendar
from dateutil.rrule import DAILY, MONTHLY, WEEKLY, YEARLY, rrule, rrulestr
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core.validators import validate_email
from django.core.validators import RegexValidator, validate_email
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _
from pretix.base.templatetags.rich_text import URL_RE
# This file is based on an earlier version of pretix which was released under the Apache License 2.0. The full text of
# the Apache License 2.0 can be obtained at <http://www.apache.org/licenses/LICENSE-2.0>.
#
@@ -113,6 +115,33 @@ def multimail_validate(val):
return s
class RegexValidatorInverseMatchAndParam(RegexValidator):
inverse_match = True
def __call__(self, value):
regex_matches = self.regex.search(str(value))
if regex_matches:
raise ValidationError(
self.message,
code=self.code,
params={
"value": value,
"match": regex_matches.group(0) if regex_matches else "",
}
)
class NoUrlValidator(RegexValidatorInverseMatchAndParam):
regex = URL_RE
def __init__(self, **kwargs):
if not kwargs.get("message"):
kwargs["message"] = _('You entered an URL, which is not allowed. Please remove %(match)s from your input.')
if not kwargs.get("code"):
kwargs["code"] = "contains_url"
super().__init__(**kwargs)
class RRuleValidator:
def __init__(self, enforce_simple=False):
self.enforce_simple = enforce_simple

View File

@@ -34,11 +34,11 @@
# License for the specific language governing permissions and limitations under the License.
from collections import defaultdict
from datetime import datetime
from decimal import Decimal
from typing import Optional
import bleach
import dateutil.parser
from django.dispatch import receiver
from django.urls import reverse
from django.utils.formats import date_format
@@ -248,7 +248,7 @@ class OrderValidFromChanged(OrderChangeLogEntryType):
def display_prefixed(self, event: Event, logentry: LogEntry, data):
return _('The validity start date for position #{posid} has been changed to {value}.').format(
posid=data.get('positionid', '?'),
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get(
value=date_format(datetime.fromisoformat(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get(
'new_value') else ''
)
@@ -260,7 +260,7 @@ class OrderValidUntilChanged(OrderChangeLogEntryType):
def display_prefixed(self, event: Event, logentry: LogEntry, data):
return _('The validity end date for position #{posid} has been changed to {value}.').format(
posid=data.get('positionid', '?'),
value=date_format(dateutil.parser.parse(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get('new_value') else ''
value=date_format(datetime.fromisoformat(data.get('new_value')), 'SHORT_DATETIME_FORMAT') if data.get('new_value') else ''
)
@@ -364,7 +364,7 @@ class CheckinErrorLogEntryType(OrderLogEntryType):
data['posid'] = logentry.parsed_data.get('positionid', '?')
if 'datetime' in data:
dt = dateutil.parser.parse(data.get('datetime'))
dt = datetime.fromisoformat(data.get('datetime'))
if abs((logentry.datetime - dt).total_seconds()) > 5 or data.get('forced'):
if event:
data['datetime'] = date_format(dt.astimezone(event.timezone), "SHORT_DATETIME_FORMAT")
@@ -430,7 +430,7 @@ class OrderPrintLogEntryType(OrderLogEntryType):
return _('Position #{posid} has been printed at {datetime} with type "{type}".').format(
posid=data.get('positionid'),
datetime=date_format(
dateutil.parser.parse(data["datetime"]).astimezone(logentry.event.timezone),
datetime.fromisoformat(data["datetime"]).astimezone(logentry.event.timezone),
"SHORT_DATETIME_FORMAT"
) if logentry.event else data["datetime"],
type=dict(PrintLog.PRINT_TYPES)[data["type"]],
@@ -985,7 +985,7 @@ class LegacyCheckinLogEntryType(OrderLogEntryType):
def display(self, logentry, data):
# deprecated
dt = dateutil.parser.parse(data.get('datetime'))
dt = datetime.fromisoformat(data.get('datetime'))
tz = logentry.event.timezone
dt_formatted = date_format(dt.astimezone(tz), "SHORT_DATETIME_FORMAT")
if 'list' in data:

View File

@@ -89,7 +89,9 @@
</button>
</div>
</form>
{{ items|json_script:"items" }}
{% if items %}
{{ items|json_script:"items" }}
{% endif %}
{% compress js %}
<script type="text/javascript" src="{% static "d3/d3.v6.js" %}"></script>

View File

@@ -134,6 +134,39 @@
</div>
{% endif %}
{% if invoice_qualified and order.invoice_dirty %}
<div class="alert alert-warning">
<p>
{% blocktrans trimmed %}
This order was changed after the last invoice was generated. A new invoice was not generated yet, because invoices are configured to be generated on payment or if required by the payment method.
A new invoice will be generated once the customer pays the invoice or selects a payment method that requires an invoice.
{% endblocktrans %}
</p>
{% if "event.orders:write" in request.eventpermset %}
<p>
{% if uncancelled_invoice %}
<form action="{% url "control:event.order.reissueinvoice" event=request.event.slug organizer=request.event.organizer.slug code=order.code id=uncancelled_invoice.pk %}"
method="post">
{% csrf_token %}
<button class="btn btn-default" type="submit">
{% blocktrans trimmed %}
Reissue invoice
{% endblocktrans %}
</button>
</form>
{% elif can_generate_invoice %}
<form method="post" action="{% url "control:event.order.geninvoice" event=request.event.slug organizer=request.event.organizer.slug code=order.code %}">
{% csrf_token %}
<button class="btn btn-default">
{% trans "Generate invoice" %}
</button>
</form>
{% endif %}
</p>
{% endif %}
</div>
{% endif %}
<div class="row">
<div class="col-xs-12 col-lg-10">
{% for cr in order.cancellation_requests.all %}
@@ -553,7 +586,7 @@
<span class="fa fa-print"></span>
{{ pl.datetime|date:"SHORT_DATETIME_FORMAT" }}
{{ pl.get_type_display }}
({{ pl.source }}{% if pl.device %}, #{{ pl.device.device_id }}{% endif %})
({{ pl.source }}{% if pl.device %}, {{ pl.device.name }} - #{{ pl.device.device_id }}{% endif %})
{% if not pl.successful %}<span class="fa fa-warning fa-fw"></span>{% endif %}
<br>
{% endfor %}

View File

@@ -23,9 +23,9 @@
<legend>{% trans "How should the refund be sent?" %}</legend>
<p>
{% blocktrans trimmed %}
Any payments that you selected for automatical refunds will be immediately communicate the refund
request to the respective payment provider. Manual refunds will be created as pending refunds, you
can then later mark them as done once you actually transferred the money back to the customer.
Any payments you selected for automatic refunds will have the refund request sent immediately to the
respective payment provider. Manual refunds will be created as pending refunds, which you can later
mark as done once you have actually transferred the money back to the customer.
{% endblocktrans %}
</p>

View File

@@ -108,7 +108,7 @@
</a>
</p>
{% endif %}
<form action="{% url "control:organizer.device.bulk_edit" organizer=request.organizer.slug %}" method="post">
<form action="#will-be-overridden" method="post">
{% csrf_token %}
{% for field in filter_form %}
{{ field.as_hidden }}

View File

@@ -554,6 +554,9 @@ class OrderDetail(OrderView):
ctx['download_buttons'] = self.download_buttons
ctx['payment_refund_sum'] = self.order.payment_refund_sum
ctx['pending_sum'] = self.order.pending_sum
ctx['uncancelled_invoice'] = self.order.invoices.exclude(
Exists(self.order.invoices.filter(refers=OuterRef('pk'), is_cancellation=True))
).exclude(is_cancellation=True).first()
return ctx

View File

@@ -531,6 +531,7 @@ class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateVi
@transaction.atomic
def form_valid(self, form):
self.object = form.save()
self.save_formset(self.object)
self.save_cl_formset(self.object)
self.save_meta()
@@ -569,7 +570,7 @@ class SubEventUpdate(EventPermissionRequiredMixin, SubEventEditorMixin, UpdateVi
f.subevent = self.object
f.save()
tickets.invalidate_cache.apply_async(kwargs={'event': self.request.event.pk})
return super().form_valid(form)
return HttpResponseRedirect(self.get_success_url())
def get_success_url(self) -> str:
return reverse('control:event.subevents', kwargs={

View File

@@ -8,18 +8,17 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:03+0000\n"
"PO-Revision-Date: 2025-04-08 18:00+0000\n"
"Last-Translator: Menaouer Chaabi "
"<98581961+DerJimno@users.noreply.github.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix/ar/"
">\n"
"PO-Revision-Date: 2026-05-19 04:16+0000\n"
"Last-Translator: Khalid Shaheen <khalid.shaheen@gmail.com>\n"
"Language-Team: Arabic <https://translate.pretix.eu/projects/pretix/pretix/"
"ar/>\n"
"Language: ar\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Weblate 5.10.4\n"
"X-Generator: Weblate 2026.5\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -39,7 +38,7 @@ msgstr "العربية"
#: pretix/_base_settings.py:91
msgid "Basque"
msgstr ""
msgstr "الباسكية"
#: pretix/_base_settings.py:92
msgid "Catalan"
@@ -59,7 +58,7 @@ msgstr "التشيكية"
#: pretix/_base_settings.py:96
msgid "Croatian"
msgstr ""
msgstr "الكرواتية"
#: pretix/_base_settings.py:97
msgid "Danish"
@@ -91,7 +90,7 @@ msgstr "اليونانية"
#: pretix/_base_settings.py:104
msgid "Hebrew"
msgstr ""
msgstr "العبرية"
#: pretix/_base_settings.py:105
msgid "Indonesian"
@@ -103,7 +102,7 @@ msgstr "الإيطالية"
#: pretix/_base_settings.py:107
msgid "Japanese"
msgstr ""
msgstr "اليابانية"
#: pretix/_base_settings.py:108
msgid "Latvian"
@@ -147,7 +146,7 @@ msgstr "الأسبانية"
#: pretix/_base_settings.py:118
msgid "Spanish (Latin America)"
msgstr ""
msgstr "الإسبانية (أميركا اللاتينية)"
#: pretix/_base_settings.py:119
msgid "Turkish"
@@ -293,41 +292,28 @@ msgid "The bundled item must not have bundles on its own."
msgstr "يجب ألا يحتوي العنصر المجمع على حزم بمفرده."
#: pretix/api/serializers/item.py:235
#, fuzzy
#| msgid "The payment is too late to be accepted."
msgid "The program start must not be empty."
msgstr "فات الأوان لقبول الدفع."
msgstr "يجب ألا يكون موعد بداية البرنامج فارغ."
#: pretix/api/serializers/item.py:239
#, fuzzy
#| msgid "The payment is too late to be accepted."
msgid "The program end must not be empty."
msgstr "فات الأوان لقبول الدفع."
msgstr "يجب ألا يكون موعد نهاية البرنامج فارغ."
#: pretix/api/serializers/item.py:242 pretix/base/models/items.py:2322
#, fuzzy
#| msgid "The maximum count needs to be greater than the minimum count."
msgid "The program end must not be before the program start."
msgstr "يجب أن يكون الحد الأقصى للعدد أكبر من الحد الأدنى للعد."
msgstr "يجب ألا يكون موعد نهاية البرنامج سابق لموعد بدايته."
#: pretix/api/serializers/item.py:247 pretix/base/models/items.py:2316
#, fuzzy
#| msgid "You can not select a subevent if your event is not an event series."
msgid "You cannot use program times on an event series."
msgstr ""
"لا يمكنك تحديد فعالية فرعية إذا لم تكن الفعالية الخاصة بك سلسلة فعاليات."
msgstr "لا يمكنك استخدام أوقات البرنامج لسلسلة من الفعاليات."
#: pretix/api/serializers/item.py:337
#, fuzzy
#| msgid ""
#| "Updating add-ons, bundles, or variations via PATCH/PUT is not supported. "
#| "Please use the dedicated nested endpoint."
msgid ""
"Updating add-ons, bundles, program times or variations via PATCH/PUT is not "
"supported. Please use the dedicated nested endpoint."
msgstr ""
"تحديث الإضافات، أو الحزم، أو المتغيرات عن طريق PATCH/PUT غير مدعوم. الرجاء "
"استخدام نقطة نهاية المتداخلة المخصصة."
"لا يوجد دعم لتحديث الإضافات، أو الحزم، أو مواعيد البرامج، أو المتغيرات عبر "
"طريقتي PATCH/PUT. يُرجى استخدام نقطة النهاية المتداخلة المخصصة لذلك."
#: pretix/api/serializers/item.py:345
msgid "Only admission products can currently be personalized."
@@ -411,10 +397,8 @@ msgstr "توجد مسبقا بطاقة هدايا بنفس السر في حسا
#: pretix/api/serializers/organizer.py:495
#: pretix/control/views/organizer.py:1039
#, fuzzy
#| msgid "Account information"
msgid "Account invitation"
msgstr "معلومات الحساب"
msgstr "دعوة إلى فتح حساب"
#: pretix/api/serializers/organizer.py:516
#: pretix/control/views/organizer.py:1138
@@ -499,47 +483,35 @@ msgstr "تم تغيير عنوان اتصال الطلب"
#: pretix/api/webhooks.py:331 pretix/base/notifications.py:281
#: pretix/control/templates/pretixcontrol/event/mail.html:102
msgid "Order changed"
msgstr "تم تغيير الطلب."
msgstr "تم تغيير الطلب"
#: pretix/api/webhooks.py:335
#, fuzzy
#| msgid "Enable payment method"
msgid "Refund of payment created"
msgstr "تمكين طريقة الدفع"
msgstr "تم إنشاء طلب استرداد الدفع"
#: pretix/api/webhooks.py:339 pretix/base/notifications.py:293
msgid "External refund of payment"
msgstr "استرداد الدفع الخارجي"
msgstr "استرداد خارجي للمدفوعات"
#: pretix/api/webhooks.py:343
#, fuzzy
#| msgid "Text (requested by user)"
msgid "Refund of payment requested by customer"
msgstr "النص (عن طريق المستخدم المطلوب)"
msgstr "استرداد المبلغ بناءً على طلب العميل"
#: pretix/api/webhooks.py:347
#, fuzzy
#| msgid "Payment completed."
msgid "Refund of payment completed"
msgstr "تم السداد."
msgstr "تم إتمام استرداد الدفع"
#: pretix/api/webhooks.py:351
#, fuzzy
#| msgid "Refund {local_id} has been canceled."
msgid "Refund of payment canceled"
msgstr "تم إلغاء استرداد {local_id}."
msgstr "إلغاء استرداد الدفع"
#: pretix/api/webhooks.py:355
#, fuzzy
#| msgid "Refund order"
msgid "Refund of payment failed"
msgstr "أجل استرداد"
msgstr "فشل استرداد الدفع"
#: pretix/api/webhooks.py:359
#, fuzzy
#| msgid "Payment confirmation date"
msgid "Payment confirmed"
msgstr "تاريخ الدفع تأكيدا"
msgstr "تم تأكيد الدفع"
#: pretix/api/webhooks.py:363
msgid "Order approved"
@@ -550,14 +522,12 @@ msgid "Order denied"
msgstr "تم رفض الطلب"
#: pretix/api/webhooks.py:371
#, fuzzy
#| msgid "Order denied"
msgid "Order deleted"
msgstr "تم رفض الطلب"
msgstr "تم حذف الطلب"
#: pretix/api/webhooks.py:375
msgid "Ticket checked in"
msgstr "تم تسجيل التذكرة"
msgstr "تم تسجيل دخول التذكرة"
#: pretix/api/webhooks.py:379
msgid "Ticket check-in reverted"
@@ -572,10 +542,8 @@ msgid "Event details changed"
msgstr "تم تغيير تفاصيل الفعالية"
#: pretix/api/webhooks.py:391
#, fuzzy
#| msgid "Event date"
msgid "Event deleted"
msgstr "تاريخ الفعالية"
msgstr "تم حذف الفعالية"
#: pretix/api/webhooks.py:395
msgctxt "subevent"
@@ -593,58 +561,44 @@ msgid "Event series date deleted"
msgstr "تم حذف تاريخ سلسلة الفعاليات"
#: pretix/api/webhooks.py:407
#, fuzzy
#| msgid "Product name"
msgid "Product changed"
msgstr "اسم المنتج"
msgstr "تم تغيير المنتج"
#: pretix/api/webhooks.py:408
msgid ""
"This includes product added or deleted and changes to nested objects like "
"variations or bundles."
msgstr ""
"يشمل ذلك المنتجات التي تمت إضافتها أو حذفها، والتغييرات التي طرأت على "
"الكائنات المتداخلة، مثل المتغيرات أو الحزم."
#: pretix/api/webhooks.py:413
#, fuzzy
#| msgid "Shop not live"
msgid "Shop taken live"
msgstr "تسوق لا يعيش"
msgstr "تم إطلاق المتجر"
#: pretix/api/webhooks.py:417
#, fuzzy
#| msgid "The shop has been taken offline."
msgid "Shop taken offline"
msgstr "وقد اتخذت المحل حاليا."
msgstr "تم إيقاف المتجر مؤقتاً"
#: pretix/api/webhooks.py:421
#, fuzzy
#| msgid "The order has been reactivated."
msgid "Test-Mode of shop has been activated"
msgstr "تم إعادة تنشيط الطلب."
msgstr "تم تفعيل وضع الاختبار للمتجر"
#: pretix/api/webhooks.py:425
#, fuzzy
#| msgid "The order has been reactivated."
msgid "Test-Mode of shop has been deactivated"
msgstr "تم إعادة تنشيط الطلب."
msgstr "تم إلغاء تفعيل وضع الاختبار للمتجر"
#: pretix/api/webhooks.py:429
#, fuzzy
#| msgid "Waiting list entry"
msgid "Waiting list entry added"
msgstr "دخول قائمة الانتظار"
msgstr "تم إضافة قيد إلى قائمة الانتظار"
#: pretix/api/webhooks.py:433
#, fuzzy
#| msgid "Waiting list entry"
msgid "Waiting list entry changed"
msgstr "دخول قائمة الانتظار"
msgstr "تم تغيير قيد قائمة الانتظار"
#: pretix/api/webhooks.py:437
#, fuzzy
#| msgid "Waiting list entry"
msgid "Waiting list entry deleted"
msgstr "دخول قائمة الانتظار"
msgstr "تم حذف قيد قائمة الانتظار"
#: pretix/api/webhooks.py:441
#, fuzzy

File diff suppressed because it is too large Load Diff

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:03+0000\n"
"PO-Revision-Date: 2026-03-27 09:03+0000\n"
"Last-Translator: Ivano Voghera <ivano.voghera@gmail.com>\n"
"PO-Revision-Date: 2026-05-12 04:00+0000\n"
"Last-Translator: Stefano Campus <stefano.campus@regione.piemonte.it>\n"
"Language-Team: Italian <https://translate.pretix.eu/projects/pretix/pretix/"
"it/>\n"
"Language: it\n"
@@ -17,7 +17,7 @@ msgstr ""
"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.16.2\n"
"X-Generator: Weblate 5.17.1\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -8598,6 +8598,8 @@ msgid ""
"Includes the ability to give someone (including oneself) additional "
"permissions."
msgstr ""
"Consente di assegnare a qualcuno (compreso se stessi) autorizzazioni "
"aggiuntive."
#: pretix/base/permissions.py:298 pretix/control/navigation.py:608
#: pretix/control/templates/pretixcontrol/organizers/customers.html:6
@@ -8609,13 +8611,14 @@ msgstr "Indirizzi Email (file di testo)"
#: pretix/base/permissions.py:310 pretix/control/navigation.py:666
#: pretix/control/navigation.py:673
msgid "Devices"
msgstr ""
msgstr "Dispositivi"
#: pretix/base/permissions.py:316
msgid ""
"Includes the ability to give access to events and data oneself does not have "
"access to."
msgstr ""
"Consente di concedere l'accesso a eventi e dati a cui non si ha accesso."
#: pretix/base/permissions.py:321
#, fuzzy
@@ -8747,6 +8750,8 @@ msgid ""
"Some products can no longer be purchased and have been removed from your "
"cart for the following reason: %s"
msgstr ""
"Alcuni prodotti non sono più disponibili e sono stati rimossi dal tuo "
"carrello per il seguente motivo: %s"
#: pretix/base/services/cart.py:117
msgid ""
@@ -10060,6 +10065,8 @@ msgid ""
"For business customers, compute taxes based on net total. For individuals, "
"use line-based rounding"
msgstr ""
"Per i clienti aziendali, calcolare le imposte sul totale al netto. Per i "
"privati, applicare l'arrotondamento per singola voce"
#: pretix/base/settings.py:85
msgid "Compute taxes based on net total with stable gross prices"
@@ -10096,6 +10103,8 @@ msgstr ""
#: pretix/base/settings.py:190
msgid "Require login to access order confirmation pages"
msgstr ""
"È necessario effettuare l'accesso per visualizzare le pagine di conferma "
"dell'ordine"
#: pretix/base/settings.py:191
msgid ""

View File

@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:03+0000\n"
"PO-Revision-Date: 2026-04-20 08:07+0000\n"
"PO-Revision-Date: 2026-05-12 06:34+0000\n"
"Last-Translator: Yasunobu YesNo Kawaguchi <kawaguti@gmail.com>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix/"
"ja/>\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.17\n"
"X-Generator: Weblate 5.17.1\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -4441,7 +4441,7 @@ msgstr "全ての製品(新規に作成されたものを含む)"
#: pretix/base/models/checkin.py:56 pretix/plugins/badges/exporters.py:436
#: pretix/plugins/checkinlists/exporters.py:854
msgid "Limit to products"
msgstr "商品の上限"
msgstr "対象製品を限定"
#: pretix/base/models/checkin.py:60
msgid ""
@@ -6896,8 +6896,8 @@ msgstr "免税輸出品目、VAT非課税"
msgctxt "tax_code"
msgid "VAT exempt for EEA intra-community supply of goods and services"
msgstr ""
"EEA欧州経済領域域内事業者間取引における品・サービス供給のVAT(付加価値"
"税)免税"
"EEA(欧州経済領域)域内事業者間取引における品・サービス供給のVAT(付加価値税)"
"免税"
#: pretix/base/models/tax.py:186
msgid "Special cases"
@@ -7144,10 +7144,10 @@ msgid ""
"usages in some cases can be lower than this limit, e.g. in case of "
"cancellations."
msgstr ""
"複数1を超える値に設定した場合、バウチャーは初回使用時にこの数の製品と引き"
"換える必要があります。その後の使用では、より少ない数の製品にも使用できます。"
"ただし、キャンセルなどの場合には、合計使用回数がこの限を下回ることがありま"
"。"
"1より大きい値を設定すると、バウチャーを最初に使用する際に、この数の製品に対し"
"て引き換える必要があります。2回目以降の使用では、これより少ない数の製品に対し"
"ても使用できます。この場合、キャンセルなどにより、合計使用回数がこの限を"
"下回ることがある点にご注意ください。"
#: pretix/base/models/vouchers.py:217
msgid ""
@@ -8059,10 +8059,8 @@ msgstr ""
"2x アドオン2"
#: pretix/base/pdf.py:383
#, fuzzy
#| msgid "List of Add-Ons"
msgid "List of Checked-In Add-Ons"
msgstr "アドオンのリスト"
msgstr "チェックイン済みアドオン一覧"
#: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537
#: pretix/control/forms/filter.py:1539
@@ -9019,10 +9017,8 @@ msgid "Czech National Bank"
msgstr "チェコ国立銀行"
#: pretix/base/services/currencies.py:41
#, fuzzy
#| msgid "Czech National Bank"
msgid "National Bank of Poland"
msgstr "チェコ国立銀行"
msgstr "ポーランド国立銀行"
#: pretix/base/services/export.py:95 pretix/base/services/export.py:155
msgid ""
@@ -10068,14 +10064,10 @@ msgid ""
msgstr "チェコ国立銀行の日次レートに基づいて、請求書の金額がCZK以外の場合。"
#: pretix/base/settings.py:577 pretix/base/settings.py:586
#, fuzzy
#| msgid ""
#| "Based on Czech National Bank daily rates, whenever the invoice amount is "
#| "not in CZK."
msgid ""
"Based on National Bank of Poland daily rates, whenever the invoice amount is "
"not in PLN."
msgstr "チェコ国立銀行の日次レートに基づいて、請求書の金額がCZK以外の場合。"
msgstr "ポーランド国立銀行の日次レートに基づいて、請求書の金額がPLN以外の場合。"
#: pretix/base/settings.py:597
msgid "Require invoice address"
@@ -15956,10 +15948,8 @@ msgid "Allow to overbook quotas when performing this operation"
msgstr "この操作を実行する際にクォータの超過予約を許可する"
#: pretix/control/forms/orders.py:335
#, fuzzy
#| msgid "Number of orders"
msgid "Number of products to add"
msgstr "注文数"
msgstr "追加する製品の数"
#: pretix/control/forms/orders.py:344
msgid "Add-on to"
@@ -15991,10 +15981,8 @@ msgstr ""
"さい"
#: pretix/control/forms/orders.py:441
#, fuzzy
#| msgid "You can not select the same seat multiple times."
msgid "You can not choose a seat when adding multiple products at once."
msgstr "同じ席を複数回選択することはできません。"
msgstr "複数の製品を同時に追加する場合、座席を選択することはできません。"
#: pretix/control/forms/orders.py:478 pretix/control/forms/orders.py:482
#: pretix/control/forms/orders.py:510 pretix/control/forms/orders.py:552
@@ -16596,7 +16584,7 @@ msgstr "週末の日"
#: pretix/control/forms/subevents.py:106
msgctxt "subevent"
msgid "Skip dates that overlap with any existing date"
msgstr ""
msgstr "既存の日付と重複する日付をスキップする"
#: pretix/control/forms/subevents.py:109
msgctxt "subevent"
@@ -16606,6 +16594,9 @@ msgid ""
"This respects even inactive dates and works best if all dates have both a "
"start and end time."
msgstr ""
"これは、すべての日付が同じ場所で行われ、既存の特別イベントと競合して重複した"
"日付が作成されない場合に有用です。これは、非アクティブな日付さえも尊重し、す"
"べての日付に開始時刻と終了時刻の両方がある場合に最も効果的です。"
#: pretix/control/forms/subevents.py:128
msgid "Keep the current values"
@@ -22963,12 +22954,11 @@ msgid ""
"total number of tickets sold and the number of a specific ticket type at the "
"same time."
msgstr ""
"製品を実際に利用可能にするには、クォータも必要です。クォータは、pretixが製品"
"のインスタンスをいくつ販売するかを定義します。これにより、イベント無制限"
"参加者を受け入れることができるか、参加者数が制限されるかを設定できます。より"
"複雑な要件を満たすために、製品を複数のクォータに割り当てることができます。例"
"えば、販売されるチケットの総数と特定のチケット種別の数を同時に制限したい場合"
"などです。"
"製品を実際に販売可能にするには、クォータも必要です。クォータは、製品をどれだ"
"けpretixが販売するかを定義します。これにより、イベントの参加者数を無制限にす"
"るか、人数を制限するかを設定できます。1つの製品を複数のクォータに割り当てるこ"
"とで、より複雑な要件にも対応できます。たとえば、販売するチケットの総数と特定"
"のチケット種別の数を同時に制限したい場合などです。"
#: pretix/control/templates/pretixcontrol/items/quotas.html:25
msgid "Your search did not match any quotas."
@@ -23685,7 +23675,7 @@ msgid ""
"this product was part of the discount calculation for a different product in "
"this order."
msgstr ""
"自動割引によりこの品の価格が引き下げられたか、同じ注文内の別の品に対する"
"自動割引によりこの品の価格が引き下げられたか、同じ注文内の別の品に対する"
"割引計算の対象になっています。"
#: pretix/control/templates/pretixcontrol/order/index.html:496
@@ -29425,7 +29415,7 @@ msgstr "一度に10万以上の日付を作成しないでください。"
#: pretix/control/views/subevents.py:966
msgid "All dates would be skipped because they conflict with existing dates."
msgstr ""
msgstr "すべての日付は、既存の日付と衝突するため、スキップされます。"
#: pretix/control/views/subevents.py:1102
#, python-brace-format
@@ -34613,7 +34603,7 @@ msgid ""
"changed because they are not on sale:"
msgstr ""
"このアドオンカテゴリで選択された製品の中には、現在セール対象外のため変更でき"
"ない品があります"
"ない品があります:"
#: pretix/presale/templates/pretixpresale/event/fragment_addon_choice.html:392
msgid "There are no add-ons available for this product."

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-03-23 21:00+0000\n"
"Last-Translator: Hijiri Umemoto <hijiri@umemoto.org>\n"
"PO-Revision-Date: 2026-05-12 06:34+0000\n"
"Last-Translator: Yasunobu YesNo Kawaguchi <kawaguti@gmail.com>\n"
"Language-Team: Japanese <https://translate.pretix.eu/projects/pretix/pretix-"
"js/ja/>\n"
"Language: ja\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.16.2\n"
"X-Generator: Weblate 5.17.1\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -572,7 +572,7 @@ msgstr "未入場"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:289
msgid "Error: Product not found!"
msgstr "エラー:品が見つかりません!"
msgstr "エラー:品が見つかりません!"
#: pretix/static/pretixcontrol/js/ui/checkinrules.js:296
msgid "Error: Variation not found!"
@@ -743,7 +743,7 @@ msgstr "カートの有効期限が近づいています。"
#: pretix/static/pretixpresale/js/ui/cart.js:62
msgid "The items in your cart are reserved for you for one minute."
msgid_plural "The items in your cart are reserved for you for {num} minutes."
msgstr[0] "カート内の品はあと {num} 分間確保されています。"
msgstr[0] "カート内の品はあと {num} 分間確保されています。"
#: pretix/static/pretixpresale/js/ui/cart.js:83
msgid "Your cart has expired."
@@ -754,7 +754,7 @@ msgid ""
"The items in your cart are no longer reserved for you. You can still "
"complete your order as long as they're available."
msgstr ""
"カート内の品の確保期限が切れました。在庫があれば、このまま注文を完了するこ"
"カート内の品の確保期限が切れました。在庫があれば、このまま注文を完了するこ"
"とができます。"
#: pretix/static/pretixpresale/js/ui/cart.js:87
@@ -987,7 +987,7 @@ msgid ""
"You currently have an active cart for this event. If you select more "
"products, they will be added to your existing cart."
msgstr ""
"このイベントのカートに品が入っています。品を追加すると、既存のカートに追"
"このイベントのカートに品が入っています。品を追加すると、既存のカートに追"
"加されます。"
#: pretix/static/pretixpresale/js/widget/widget.js:57

View File

@@ -8,16 +8,16 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:03+0000\n"
"PO-Revision-Date: 2026-02-14 06:10+0000\n"
"Last-Translator: Nate Horst <nate@agcthailand.org>\n"
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/"
">\n"
"PO-Revision-Date: 2026-05-20 10:58+0000\n"
"Last-Translator: Phumraphee Sae-tang <phumraphee@gmail.com>\n"
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix/th/>"
"\n"
"Language: th\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.15.2\n"
"X-Generator: Weblate 2026.5\n"
#: pretix/_base_settings.py:87
msgid "English"
@@ -395,10 +395,8 @@ msgstr "มีบัตรของขวัญที่มีรหัสลั
#: pretix/api/serializers/organizer.py:495
#: pretix/control/views/organizer.py:1039
#, fuzzy
#| msgid "Account information"
msgid "Account invitation"
msgstr "ข้อมูลบัญชี"
msgstr "คำเชิญเข้าร่วมบัญชี"
#: pretix/api/serializers/organizer.py:516
#: pretix/control/views/organizer.py:1138
@@ -634,22 +632,16 @@ msgid "Customer account anonymized"
msgstr "กำหนดบัญชีลูกค้าเป็นแบบไม่ระบุตัวตนแล้ว"
#: pretix/api/webhooks.py:470
#, fuzzy
#| msgid "Gift card code"
msgid "Gift card added"
msgstr "รหัสบัตรของขวัญ"
msgstr "บัตรของขวัญได้ถูกเพิ่มแล้ว"
#: pretix/api/webhooks.py:474
#, fuzzy
#| msgid "Gift card code"
msgid "Gift card modified"
msgstr "รหัสบัตรของขวัญ"
msgstr "บัตรของขวัญได้ถูกแก้ไขแล้ว"
#: pretix/api/webhooks.py:478
#, fuzzy
#| msgid "Gift card transactions"
msgid "Gift card used in transaction"
msgstr "ธุรกรรมบัตรของขวัญ"
msgstr "บัตรของขวัญที่ถูกใช้ในธุรกรรม"
#: pretix/base/addressvalidation.py:100 pretix/base/addressvalidation.py:103
#: pretix/base/addressvalidation.py:108 pretix/base/forms/questions.py:1060
@@ -721,7 +713,7 @@ msgid "Your password may not be the same as your previous password."
msgid_plural ""
"Your password may not be the same as one of your %(history_length)s previous "
"passwords."
msgstr[0] ""
msgstr[0] "รหัสผ่านของคุณอาจจะไม่เหมือนกับรหัสผ่านเก่าของคุณ %(history_length)s"
#: pretix/base/channels.py:168
msgid "Online shop"
@@ -2548,10 +2540,8 @@ msgid "Voucher budget usage"
msgstr "ยอดการใช้เวาเชอร์"
#: pretix/base/exporters/orderlist.py:656
#, fuzzy
#| msgid "Voucher"
msgid "Voucher tag"
msgstr "เวาเชอร์"
msgstr "ป้ายคูปอง"
#: pretix/base/exporters/orderlist.py:657
msgid "Pseudonymization ID"
@@ -3351,39 +3341,34 @@ msgid "Street and Number"
msgstr "ถนนและบ้านเลขที่"
#: pretix/base/forms/questions.py:899
#, fuzzy, python-brace-format
#| msgid "Please enter a shorter name."
#, python-brace-format
msgid "Please enter a date between {min} and {max}."
msgstr "โปรดระบุชื่อที่สั้นกว่านี้"
msgstr "กรุณาระบุวันที่ระหว่าง {min} และ {max}"
#: pretix/base/forms/questions.py:905
#, fuzzy, python-brace-format
#| msgid "Please enter a valid sales channel."
#, python-brace-format
msgid "Please enter a date no earlier than {min}."
msgstr "โปรดระบุช่องทางการขายที่ถูกต้อง"
msgstr "โปรดระบุวันที่ตั้งแต่ {min} เป็นต้นไป"
#: pretix/base/forms/questions.py:910
#, fuzzy, python-brace-format
#| msgid "Please enter a shorter name."
#, python-brace-format
msgid "Please enter a date no later than {max}."
msgstr "โปรดระบุชื่อที่สั้นกว่านี้"
msgstr "กรุณาระบุวันที่ก่อนวันที่ {max}"
#: pretix/base/forms/questions.py:948
#, python-brace-format
msgid "Please enter a date and time between {min} and {max}."
msgstr ""
msgstr "กรุณาระบุวันที่และเวลาระหว่าง {min} และ {max}"
#: pretix/base/forms/questions.py:954
#, fuzzy, python-brace-format
#| msgid "Please enter a valid sales channel."
#, python-brace-format
msgid "Please enter a date and time no earlier than {min}."
msgstr "โปรดระบุช่องทางการขายที่ถูกต้อง"
msgstr "กรุณาระบุวันที่และเวลาตั้งแต่ {min} เป็นต้นไป"
#: pretix/base/forms/questions.py:959
#, fuzzy, python-brace-format
#| msgid "Please enter a valid state."
#, python-brace-format
msgid "Please enter a date and time no later than {max}."
msgstr "โปรดระบุรัฐ/จังหวัที่ถูกต้อง"
msgstr "กรุณาระบวัที่และเวลาก่อน {max}"
#: pretix/base/forms/questions.py:1178
msgid ""
@@ -3570,27 +3555,27 @@ msgstr "รับไฟล์ PDF ทางอีเมล"
#: pretix/base/invoicing/national.py:37
msgctxt "italian_invoice"
msgid "Italian Exchange System (SdI)"
msgstr ""
msgstr "Italian Exchange System (SdI)"
#: pretix/base/invoicing/national.py:38
msgctxt "italian_invoice"
msgid "Exchange System (SdI)"
msgstr ""
msgstr "Exchange System (SdI)"
#: pretix/base/invoicing/national.py:51
msgctxt "italian_invoice"
msgid "Fiscal code"
msgstr ""
msgstr "Fiscal code"
#: pretix/base/invoicing/national.py:55
msgctxt "italian_invoice"
msgid "Address for certified electronic mail"
msgstr ""
msgstr "อีเมลสำหรับการติดต่อทางอิเล็กทรอนิกส์แบบรับรอง"
#: pretix/base/invoicing/national.py:59
msgctxt "italian_invoice"
msgid "Recipient code"
msgstr ""
msgstr "รหัสผู้รับปลายทาง"
#: pretix/base/invoicing/national.py:83
msgctxt "italian_invoice"
@@ -3600,6 +3585,10 @@ msgid ""
"in accordance with the procedures and terms set forth in No. 89757/2018 of "
"April 30, 2018, issued by the Director of the Revenue Agency."
msgstr ""
"เอกสาร PDF นี้เป็นเพียงสำเนาเพื่อการแสดงผลของใบแจ้งหนี้ และไม่ใช่ใบแจ้งหนี้ที่ใช้เพื่อวัตถุประสงค์ด้"
"านภาษีมูลค่าเพิ่ม (VAT)ใบแจ้งหนี้ฉบับสมบูรณ์ถูกจัดทำในรูปแบบ XML และส่งตามหลักเกณฑ์และวิธีการที่กำ"
"หนดในประกาศเลขที่ 89757/2018 ลงวันที่ 30 เมษายน 2018 ซึ่งออกโดยผู้อำนวยการสำนักงานสรรพา"
"กร"
#: pretix/base/invoicing/pdf.py:142
#, python-format
@@ -3847,6 +3836,7 @@ msgstr "วันที่จัดกิจกรรม: {date_range}"
msgid ""
"A Peppol participant ID always starts with a prefix, followed by a colon (:)."
msgstr ""
"รหัสผู้เข้าร่วม Peppol ต้องเริ่มต้นด้วย prefix และตามด้วยเครื่องหมาย \":\""
#: pretix/base/invoicing/peppol.py:140
#, python-format
@@ -3854,6 +3844,8 @@ msgid ""
"The Peppol participant ID prefix %(number)s is not known to our system. "
"Please reach out to us if you are sure this ID is correct."
msgstr ""
"ระบบของเราไม่รองรับ prefix ของ Peppol participant ID หมายเลข %(number)s หากท่านมั่"
"นใจว่ารหัสดังกล่าวถูกต้อง กรุณาติดต่อเราเพื่อขอความช่วยเหลือ"
#: pretix/base/invoicing/peppol.py:144
#, python-format
@@ -3861,23 +3853,25 @@ msgid ""
"The Peppol participant ID does not match the validation rules for the prefix "
"%(number)s. Please reach out to us if you are sure this ID is correct."
msgstr ""
"รหัส Peppol participant ID ไม่ถูกต้องตามรูปแบบของ prefix 1%(number)s หากรหัสดังกล่าวถู"
"กต้อง กรุณาติดต่อเรา"
#: pretix/base/invoicing/peppol.py:166
msgid "The Peppol participant ID is not registered on the Peppol network."
msgstr ""
msgstr "Peppol participant ID นี้ไม่ได้ลงทะเบียนอยู่ในเครือข่าย Peppol"
#: pretix/base/invoicing/peppol.py:192
msgid "Peppol participant ID"
msgstr ""
msgstr "Peppol participant ID นี้ไม่ได้ลงทะเบียนอยู่ในเครือข่าย Peppol"
#: pretix/base/invoicing/peppol.py:211
msgid "The Peppol participant ID does not match your VAT ID."
msgstr ""
msgstr "Peppol participant ID ไม่ตรงกับหมายเลข VAT ID ของคุณ"
#: pretix/base/invoicing/peppol.py:214
msgctxt "peppol_invoice"
msgid "Visual copy"
msgstr ""
msgstr "สำเนาเพื่อแสดงผล"
#: pretix/base/invoicing/peppol.py:219
msgctxt "peppol_invoice"
@@ -3886,12 +3880,16 @@ msgid ""
"invoice for VAT purposes. The original invoice is issued in XML format and "
"transmitted through the Peppol network."
msgstr ""
"เอกสาร PDF นี้เป็นเพียงสำเนาเพื่อการแสดงผลของใบแจ้งหนี้ และไม่ถือเป็นใบแจ้งหนี้เพื่อวัตถุประสงค์ด้"
"านภาษีมูลค่าเพิ่ม (VAT) ใบแจ้งหนี้ต้นฉบับถูกจัดทำในรูปแบบ XML และส่งผ่านเครือข่าย Peppol"
#: pretix/base/logentrytype_registry.py:43
msgid ""
"The relevant plugin is currently not active. To activate it, click here to "
"go to the plugin settings."
msgstr ""
"ปลั๊กอินที่เกี่ยวข้องยังไม่ได้เปิดใช้งานในขณะนี้ หากต้องการเปิดใช้งาน คลิกที่นี่เพื่อไปยังหน้าการตั้งค่าปลั๊ก"
"อิน"
#: pretix/base/logentrytype_registry.py:53
msgid "The relevant plugin is currently not active."
@@ -4229,23 +4227,21 @@ msgstr "อนุญาตให้ข้ามการตรวจสอบโ
#: pretix/control/templates/pretixcontrol/vouchers/detail.html:70
#: pretix/control/views/vouchers.py:121
msgid "Price effect"
msgstr ""
msgstr "ผลต่างด้านราคา"
#: pretix/base/modelimport_vouchers.py:150
#, fuzzy, python-brace-format
#| msgid "Could not parse {value} as a price mode, use one of {options}."
#, python-brace-format
msgid "Could not parse {value} as a price effect, use one of {options}."
msgstr "ไม่สามารถประมวลผล {value} เป็นโหมดราคาได้ โปรดใช้ค่าใดค่าหนึ่งจาก {options}"
msgstr ""
"ไม่สามารถประมวลผล {value} เป็นค่าผลต่างด้านราคาได้ โปรดใช้ค่าใดค่าหนึ่งจาก {options}"
#: pretix/base/modelimport_vouchers.py:160 pretix/base/models/vouchers.py:248
msgid "Voucher value"
msgstr "มูลค่าเวาเชอร์"
#: pretix/base/modelimport_vouchers.py:165
#, fuzzy
#| msgid "It is pointless to set a value without a price mode."
msgid "It is pointless to set a value without a price effect."
msgstr "การกำหนดมูลค่าจะไม่มีผลหากไม่ได้กำหนดโหมดราคา"
msgstr "การกำหนดมูลค่าจะไม่มีผลหากไม่ได้กำหนดผลต่างด้านราคา"
#: pretix/base/modelimport_vouchers.py:237 pretix/base/models/items.py:2121
#: pretix/base/models/vouchers.py:275
@@ -6177,46 +6173,41 @@ msgstr "สิ้นสุด"
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:38
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:139
msgid "queued"
msgstr ""
msgstr "อยู่ในคิว"
#: pretix/base/models/mail.py:53
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:40
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:141
msgid "being sent"
msgstr ""
msgstr "กำลังส่ง"
#: pretix/base/models/mail.py:54
#, fuzzy
#| msgid "Waiting list entry"
msgid "awaiting retry"
msgstr "รายการในรายการรอ"
msgstr "รอการลองใหม่"
#: pretix/base/models/mail.py:55
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:48
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:149
msgid "withheld"
msgstr ""
msgstr "ถูกหักไว้"
#: pretix/base/models/mail.py:57
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:50
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:151
msgid "aborted"
msgstr ""
msgstr "ยกเลิกแล้ว"
#: pretix/base/models/mail.py:58
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:52
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:153
#, fuzzy
#| msgctxt "checkin state"
#| msgid "Present"
msgid "sent"
msgstr "มา"
msgstr "ส่งแล้ว"
#: pretix/base/models/mail.py:59
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mail.html:46
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:147
msgid "bounced"
msgstr ""
msgstr "ตีกลับ"
#: pretix/base/models/memberships.py:44
#: pretix/presale/templates/pretixpresale/organizers/customer_memberships.html:28
@@ -6622,24 +6613,22 @@ msgstr ""
"ทั้งนี้ การตั้งค่าอาจใช้เวลาสักครู่เพื่อให้มีผลกับผู้ใช้ทุกคน"
#: pretix/base/models/organizer.py:384
#, fuzzy
#| msgid "Event admission"
msgid "All event permissions"
msgstr "เริ่มเปิดให้เข้างาน"
msgstr "สิทธิทั้งหมดของกิจกรรม"
#: pretix/base/models/organizer.py:385
#: pretix/control/templates/pretixcontrol/organizers/team_edit.html:34
msgid "Event permissions"
msgstr ""
msgstr "สิทธิของกิจกรรม"
#: pretix/base/models/organizer.py:386
msgid "All organizer permissions"
msgstr ""
msgstr "สิทธิขององค์กรทั้งหมด"
#: pretix/base/models/organizer.py:387
#: pretix/control/templates/pretixcontrol/organizers/team_edit.html:25
msgid "Organizer permissions"
msgstr ""
msgstr "สิทธิขององค์กร"
#: pretix/base/models/organizer.py:407
#, python-format
@@ -7889,10 +7878,8 @@ msgstr ""
"2x สินค้าเพิ่มเติม 2"
#: pretix/base/pdf.py:383
#, fuzzy
#| msgid "List of Add-Ons"
msgid "List of Checked-In Add-Ons"
msgstr "รายการสินค้าเพิ่มเติม"
msgstr "รายการส่วนเสริมที่เช็คอินแล้ว"
#: pretix/base/pdf.py:390 pretix/control/forms/filter.py:1537
#: pretix/control/forms/filter.py:1539
@@ -8073,145 +8060,129 @@ msgstr "ไฟล์เลย์เอาต์ของคุณไม่ถู
#: pretix/base/permissions.py:314 pretix/base/permissions.py:331
msgctxt "permission_level"
msgid "View"
msgstr ""
msgstr "แสดงผล"
#: pretix/base/permissions.py:164 pretix/base/permissions.py:169
#: pretix/base/permissions.py:174 pretix/base/permissions.py:179
#: pretix/base/permissions.py:286 pretix/base/permissions.py:315
#, fuzzy
#| msgid "Voucher changed"
msgctxt "permission_level"
msgid "View and change"
msgstr "แก้ไขรหัสส่วนลดแล้ว"
msgstr "แสดงและแก้ไข"
#: pretix/base/permissions.py:168
msgid "API only"
msgstr ""
msgstr "API เท่านั้น"
#: pretix/base/permissions.py:173
msgid ""
"Menu item will only show up if the user has permission for general settings."
msgstr ""
"รายการเมนูนี้จะแสดงเฉพาะผู้ใช้ที่มีสิทธิ์เข้าถึงการตั้งค่าทั่วไปเท่านั้น"
#: pretix/base/permissions.py:177 pretix/base/permissions.py:231
#: pretix/base/permissions.py:285 pretix/base/permissions.py:313
#: pretix/base/permissions.py:330
#, fuzzy
#| msgid "Read access"
msgctxt "permission_level"
msgid "No access"
msgstr "สิทธิในการอ่านข้อมูล"
msgstr "ไม่มีสิทธิในการเข้าถึง"
#: pretix/base/permissions.py:188
#: pretix/control/templates/pretixcontrol/event/settings.html:7
#: pretix/control/templates/pretixcontrol/event/settings.html:13
#: pretix/control/templates/pretixcontrol/user/settings.html:29
msgid "General settings"
msgstr ""
msgstr "การตั้งค่าทั่วไป"
#: pretix/base/permissions.py:192
msgid ""
"This includes access to all settings not listed explicitly below, including "
"plugin settings."
msgstr ""
"ซึ่งรวมถึงสิทธิ์เข้าถึงการตั้งค่าทั้งหมดที่ไม่ได้ระบุไว้ด้านล่างอย่างชัดเจน รวมถึงการตั้งค่าปลั๊กอินด้วย"
#: pretix/base/permissions.py:197
#: pretix/control/templates/pretixcontrol/event/payment.html:6
#: pretix/control/templates/pretixcontrol/event/payment_provider.html:5
msgid "Payment settings"
msgstr ""
msgstr "การตั้งค่าการชำระเงิน"
#: pretix/base/permissions.py:203
#: pretix/control/templates/pretixcontrol/event/tax.html:120
msgid "Tax settings"
msgstr ""
msgstr "การตั้งค่าเกี่ยวกับภาษี"
#: pretix/base/permissions.py:209
#, fuzzy
#| msgid "Invoice lines"
msgid "Invoicing settings"
msgstr "รายการในใบแจ้งหนี้"
msgstr "การตั้งค่าที่เกี่ยวกับใบแจ้งหนี้"
#: pretix/base/permissions.py:215
#, fuzzy
#| msgctxt "subevent"
#| msgid "Event series date added"
msgid "Event series dates"
msgstr "เพิ่มวันที่ในชุดกิจกรรมแล้ว"
msgstr "วันที่จัดงานแต่ละรอบ"
#: pretix/base/permissions.py:221
#, fuzzy
#| msgid "Product name and variation"
msgid "Products, quotas and questions"
msgstr "ชื่อสินค้าและรูปแบบสินค้า"
msgstr "สินค้า โควตา และคำถาม"
#: pretix/base/permissions.py:224
msgid "Also includes related objects like categories or discounts."
msgstr ""
msgstr "รวมถึงรายการที่เกี่ยวข้อง เช่น หมวดหมู่หรือส่วนลดด้วย"
#: pretix/base/permissions.py:232
#, fuzzy
#| msgid "Web Check-in"
msgctxt "permission_level"
msgid "Only check-in"
msgstr "เว็บเช็อิน (Web Check-in)"
msgstr "สิทธิ์สำหรับเช็อินเท่านั้น"
#: pretix/base/permissions.py:233
msgctxt "permission_level"
msgid "View all"
msgstr ""
msgstr "ดูทั้งหมด"
#: pretix/base/permissions.py:234
#, fuzzy
#| msgid "Web-based check-in"
msgctxt "permission_level"
msgid "View all and check-in"
msgstr "การเช็คอินผ่านเว็บ"
msgstr "ดูทั้งหมดและเช็คอิน"
#: pretix/base/permissions.py:235
msgctxt "permission_level"
msgid "View all and change"
msgstr ""
msgstr "ดูทั้งหมดและแก้ไข"
#: pretix/base/permissions.py:236
msgid "Includes the ability to cancel and refund individual orders."
msgstr ""
msgstr "รวมถึงสิทธิ์ในการยกเลิกและคืนเงินสำหรับคำสั่งซื้อแต่ละรายการ"
#: pretix/base/permissions.py:238
msgid "Also includes related objects like the waiting list."
msgstr ""
msgstr "รวมถึงข้อมูลที่เกี่ยวข้อง เช่น รายชื่อผู้รอคิวด้วย"
#: pretix/base/permissions.py:248
#, fuzzy
#| msgctxt "subevent"
#| msgid "Event or date information"
msgid "Full event or date cancellation"
msgstr "ข้อมูลกิจกรรมหรือวันที่"
msgstr "การยกเลิกทั้งงานหรือวันที่จัดงาน"
#: pretix/base/permissions.py:252
msgctxt "permission_level"
msgid "Not allowed"
msgstr ""
msgstr "ไม่ได้รับอนุญาต"
#: pretix/base/permissions.py:253
msgctxt "permission_level"
msgid "Allowed"
msgstr ""
msgstr "อนุญาต"
#: pretix/base/permissions.py:268
msgctxt "permission_level"
msgid "Access existing events"
msgstr ""
msgstr "เข้าถึงกิจกรรมที่มีอยู่"
#: pretix/base/permissions.py:269
msgctxt "permission_level"
msgid "Access existing and create new events"
msgstr ""
msgstr "เข้าถึงกิจกรรมที่มีอยู่และสร้างกิจกรรมใหม่"
#: pretix/base/permissions.py:271
msgid ""
"The level of access to events is determined in detail by the settings below."
msgstr ""
msgstr "การตั้งค่าด้านล่างจะกำหนดระดับการเข้าถึงกิจกรรมอย่างละเอียด"
#: pretix/base/permissions.py:275 pretix/control/navigation.py:143
#: pretix/control/navigation.py:462 pretix/control/navigation.py:512
@@ -8223,47 +8194,48 @@ msgstr ""
#: pretix/plugins/returnurl/apps.py:40
#: pretix/plugins/ticketoutputpdf/apps.py:55
msgid "Settings"
msgstr ""
msgstr "การตั้งค่า"
#: pretix/base/permissions.py:278
msgid ""
"This includes access to all organizer-level functionality not listed "
"explicitly below, including plugin settings."
msgstr ""
"ซึ่งรวมถึงสิทธิ์เข้าถึงฟังก์ชันทั้งหมดในระดับผู้จัดงานที่ไม่ได้ระบุไว้ด้านล่างอย่างชัดเจน รวมถึงการตั้งค่าปลั๊"
"กอินด้วย"
#: pretix/base/permissions.py:287
msgid ""
"Includes the ability to give someone (including oneself) additional "
"permissions."
msgstr ""
msgstr "รวมถึงสิทธิ์ในการมอบสิทธิ์เพิ่มเติมให้ผู้อื่น (รวมถึงตนเอง)"
#: pretix/base/permissions.py:298 pretix/control/navigation.py:608
#: pretix/control/templates/pretixcontrol/organizers/customers.html:6
#: pretix/control/templates/pretixcontrol/organizers/customers.html:9
msgid "Customers"
msgstr ""
msgstr "ลูกค้า"
#: pretix/base/permissions.py:310 pretix/control/navigation.py:666
#: pretix/control/navigation.py:673
msgid "Devices"
msgstr ""
msgstr "อุปกรณ์"
#: pretix/base/permissions.py:316
msgid ""
"Includes the ability to give access to events and data oneself does not have "
"access to."
msgstr ""
"รวมถึงสิทธิ์ในการมอบการเข้าถึงกิจกรรมและข้อมูลที่ตนเองไม่มีสิทธิ์เข้าถึง"
#: pretix/base/permissions.py:321
#, fuzzy
#| msgid "Seating plan"
msgid "Seating plans"
msgstr "ผังที่นั่ง"
#: pretix/base/permissions.py:327 pretix/control/navigation.py:712
#: pretix/control/templates/pretixcontrol/organizers/outgoing_mails.html:8
msgid "Outgoing emails"
msgstr ""
msgstr "อีเมลขาออก"
#: pretix/base/plugins.py:138
#: pretix/control/templates/pretixcontrol/event/quick_setup.html:132
@@ -8418,24 +8390,21 @@ msgstr ""
#, python-format
msgid "You cannot select more than %s item per order."
msgid_plural "You cannot select more than %s items per order."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "คุณไม่สามารถเลือกได้เกิน %s รายการต่อคำสั่งซื้อ"
#: pretix/base/services/cart.py:138 pretix/base/services/orders.py:1602
#, python-format
msgid "You cannot select more than %(max)s item of the product %(product)s."
msgid_plural ""
"You cannot select more than %(max)s items of the product %(product)s."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "คุณไม่สามารถเลือกสินค้า %(product)s ได้เกิน %(max)s รายการ"
#: pretix/base/services/cart.py:143 pretix/base/services/orders.py:1607
#, python-format
msgid "You need to select at least %(min)s item of the product %(product)s."
msgid_plural ""
"You need to select at least %(min)s items of the product %(product)s."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "คุณต้องเลือกสินค้า %(product)s อย่างน้อย %(min)s รายการ"
#: pretix/base/services/cart.py:148
#, python-format
@@ -8446,7 +8415,8 @@ msgid_plural ""
"We removed %(product)s from your cart as you can not buy less than %(min)s "
"items of it."
msgstr[0] ""
msgstr[1] ""
"เราได้นำสินค้า %(product)s ออกจากตะกร้าของคุณ เนื่องจากไม่สามารถซื้อสินค้านี้ต่ำกว่า %(min)s "
"รายการได้"
#: pretix/base/services/cart.py:152 pretix/base/services/orders.py:164
#: pretix/presale/templates/pretixpresale/event/index.html:170
@@ -8501,7 +8471,8 @@ msgid_plural ""
"The voucher code \"%(voucher)s\" can only be used if you select at least "
"%(number)s matching products."
msgstr[0] ""
msgstr[1] ""
"สามารถใช้โค้ดส่วนลด “%(voucher)s” ได้ก็ต่อเมื่อเลือกสินค้าที่ร่วมรายการอย่างน้อย %(number)s ร"
"ายการ"
#: pretix/base/services/cart.py:170
#, python-format
@@ -8514,7 +8485,8 @@ msgid_plural ""
"%(number)s matching products. We have therefore removed some positions from "
"your cart that can no longer be purchased like this."
msgstr[0] ""
msgstr[1] ""
"โค้ดส่วนลด “%(voucher)s” ใช้ได้เมื่อเลือกสินค้าที่เข้าเงื่อนไขอย่างน้อย %(number)s รายการ เรา"
"จึงนำบางรายการออกจากตะกร้าของคุณ เนื่องจากไม่สามารถสั่งซื้อภายใต้เงื่อนไขนี้ได้อีก"
#: pretix/base/services/cart.py:176
msgid ""
@@ -8606,7 +8578,7 @@ msgid_plural ""
"You can select at most %(max)s add-ons from the category %(cat)s for the "
"product %(base)s."
msgstr[0] ""
msgstr[1] ""
"สามารถเลือกส่วนเสริมในหมวดหมู่ %(cat)s สำหรับสินค้า %(base)s ได้ไม่เกิน %(max)s รายการ"
#: pretix/base/services/cart.py:210 pretix/base/services/orders.py:199
#, python-format
@@ -30685,7 +30657,7 @@ msgstr ""
#: pretix/plugins/stripe/payment.py:1572
msgid "iDEAL | Wero"
msgstr ""
msgstr "iDEAL | Wero"
#: pretix/plugins/stripe/payment.py:1575
msgid ""

View File

@@ -8,8 +8,8 @@ msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-04-28 09:04+0000\n"
"PO-Revision-Date: 2026-01-29 13:00+0000\n"
"Last-Translator: Nate Horst <nate@agcthailand.org>\n"
"PO-Revision-Date: 2026-05-20 10:58+0000\n"
"Last-Translator: Phumraphee Sae-tang <phumraphee@gmail.com>\n"
"Language-Team: Thai <https://translate.pretix.eu/projects/pretix/pretix-js/"
"th/>\n"
"Language: th\n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.15.2\n"
"X-Generator: Weblate 2026.5\n"
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:56
#: pretix/plugins/banktransfer/static/pretixplugins/banktransfer/ui.js:62
@@ -60,7 +60,7 @@ msgstr "PayPal Pay Later"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:41
msgid "iDEAL | Wero"
msgstr ""
msgstr "iDEAL | Wero"
#: pretix/plugins/paypal2/static/pretixplugins/paypal2/pretix-paypal.js:42
msgid "SEPA Direct Debit"
@@ -712,8 +712,7 @@ msgstr "จำนวน"
#: pretix/static/pretixcontrol/js/ui/subevent.js:112
msgid "(one more date)"
msgid_plural "({num} more dates)"
msgstr[0] ""
msgstr[1] ""
msgstr[0] "อีก {num} วัน"
#: pretix/static/pretixpresale/js/ui/cart.js:47
msgid ""
@@ -734,8 +733,7 @@ msgstr "ตะกร้าสินค้าของคุณกำลังจ
#: pretix/static/pretixpresale/js/ui/cart.js:62
msgid "The items in your cart are reserved for you for one minute."
msgid_plural "The items in your cart are reserved for you for {num} minutes."
msgstr[0] ""
msgstr[1] ""
msgstr[0] "สินค้าในตะกร้าของคุณจะถูกจองไว้ให้คุณเป็นเวลา {num} นาที"
#: pretix/static/pretixpresale/js/ui/cart.js:83
msgid "Your cart has expired."

View File

@@ -405,7 +405,7 @@ def process_banktransfers(self, job: int, data: list) -> None:
# We need to sort prefixes by length with long ones first. In case we have an event with slug
# "CONF" and one with slug "CONF2022", we want CONF2022 to match first, to avoid the parser
# thinking "2022" is already the order code.
"|".join(sorted([re.escape(p).replace("\\-", r"[\- ]*") for p in prefixes], key=lambda p: len(p), reverse=True)),
"|".join([re.escape(p).replace("\\-", r"[\- ]*") for p in sorted(prefixes, key=lambda p: len(p), reverse=True)]),
min(code_len_agg['min'] or 1, inr_len_agg['min'] or 1),
max(code_len_agg['max'] or 5, inr_len_agg['max'] or 5)
)

View File

@@ -82,7 +82,8 @@ class CheckInListMixin(BaseExporter):
widget=forms.RadioSelect(
attrs={'class': 'scrolling-choice'}
),
initial=self.event.checkin_lists.first()
initial=self.event.checkin_lists.first(),
required=True
)),
('date_range',
DateFrameField(
@@ -143,7 +144,6 @@ class CheckInListMixin(BaseExporter):
if not self.event.has_subevents:
del d['date_range']
d['list'].queryset = self.event.checkin_lists.all()
d['list'].widget = Select2(
attrs={
'data-model-select2': 'generic',
@@ -155,7 +155,6 @@ class CheckInListMixin(BaseExporter):
}
)
d['list'].widget.choices = d['list'].choices
d['list'].required = True
return d

View File

@@ -126,7 +126,7 @@ footer_link = EventPluginSignal()
Arguments: ``request``
The signal ``pretix.presale.signals.footer_link`` allows you to add links to the footer of an event page. You
are expected to return a dictionary containing the keys ``label`` and ``url``.
are expected to return a dictionary containing the keys ``label``, ``url`` and optionally ``cssclass``.
As with all event plugin signals, the ``sender`` keyword argument will contain the event.
"""

View File

@@ -80,7 +80,7 @@
<li>{{ footer_text }}</li>
{% endif %}
{% for f in footer %}
<li><a href="{% safelink f.url %}" target="_blank" rel="noopener">{{ f.label }}</a></li>
<li><a class="{{ f.cssclass }}" href="{% safelink f.url %}" target="_blank" rel="noopener">{{ f.label }}</a></li>
{% endfor %}
{% include "pretixpresale/base_footer.html" %} {# removing or hiding this might be in violation of pretix' license #}
</ul>

View File

@@ -53,7 +53,17 @@ function async_task_on_success(data) {
// hide waitingDialog when using browser's history back
waitingDialog.hide();
});
location.href = data.redirect;
if (async_task_is_download && window.self !== window.top) {
// if in an iframe, force to download an async_task_is_download
// e.g. pretix-reseller embeds order-page in iframe, which would cause ticket-PDFs to be displayed inline
var a = document.createElement("a");
a.href = data.redirect;
a.download = "";
a.target = "_blank";
a.click();
} else {
location.href = data.redirect;
}
}
$(this).trigger('pretix:async-task-success', data);
}

View File

@@ -75,10 +75,14 @@ const missingItems = computed(() => {
li.active(role="presentation")
a(href="#rules-edit", role="tab", data-toggle="tab")
span.fa.fa-edit
// space between icon and string
|
| {{ gettext("Edit") }}
li(role="presentation")
a(href="#rules-viz", role="tab", data-toggle="tab")
span.fa.fa-eye
// space between icon and string
|
| {{ gettext("Visualize") }}
//- Tab panes

View File

@@ -191,3 +191,8 @@ export const DATETIME_OPTIONS = {
close: 'fa fa-remove'
}
}
export const TIME_OPTIONS = {
...DATETIME_OPTIONS,
format: document.body.dataset.timeformat,
}

View File

@@ -17,7 +17,7 @@ export const rules = ref<any>({})
// grab rules from hidden input
const rulesInput = document.querySelector<HTMLInputElement>('#id_rules')
if (rulesInput?.value) {
rules.value = JSON.parse(rulesInput.value)
rules.value = JSON.parse(rulesInput.value) ?? {}
}
// sync back to hidden input
@@ -65,4 +65,4 @@ if (itemsEl?.textContent) {
export const productSelectURL = ref(document.querySelector('#product-select2')?.textContent)
export const variationSelectURL = ref(document.querySelector('#variations-select2')?.textContent)
export const gateSelectURL = ref(document.querySelector('#gate-select2')?.textContent)
export const gateSelectURL = ref(document.querySelector('#gates-select2')?.textContent)

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { DATETIME_OPTIONS } from './constants'
import { TIME_OPTIONS } from './constants'
const props = defineProps<{
required?: boolean
@@ -20,7 +20,7 @@ watch(() => props.value, (val) => {
onMounted(() => {
$(input.value)
.datetimepicker({
...DATETIME_OPTIONS,
...TIME_OPTIONS,
showClear: props.required,
})
.trigger('change')

View File

@@ -180,7 +180,7 @@ g
br
span(v-if="varresult !== null") {{ varresult }}
strong
| {{ op.label }} {{ rightoperand }}
| {{ op?.label}} {{ rightoperand }}
span(v-else-if="vardata && vardata.type === 'int_by_datetime'")
span.fa.fa-sign-in(v-if="variable.startsWith('entries_')")
| {{ vardata.label }}
@@ -193,21 +193,21 @@ g
br
span(v-if="varresult !== null") {{ varresult }}
strong
| {{ op.label }} {{ rightoperand }}
| {{ op?.label }} {{ rightoperand }}
span(v-else-if="vardata && variable === 'now'")
span.fa.fa-clock-o
| {{ vardata.label }}
br
span(v-if="varresult !== null") {{ varresult }}
strong
| {{ op.label }}
| {{ op?.label }}
br
span(v-if="rightoperand.buildTime[0] === 'custom'")
| {{ df(rightoperand.buildTime[1]) }}
span(v-else-if="rightoperand.buildTime[0] === 'customtime'")
| {{ tf(rightoperand.buildTime[1]) }}
span(v-if="rightoperand?.buildTime[0] === 'custom'")
| {{ df(rightoperand?.buildTime[1]) }}
span(v-else-if="rightoperand?.buildTime[0] === 'customtime'")
| {{ tf(rightoperand?.buildTime[1]) }}
span(v-else)
| {{ TEXTS[rightoperand.buildTime[0]] }}
| {{ TEXTS[rightoperand?.buildTime[0]] }}
span(v-if="operands[2]")
span(v-if="operator === 'isBefore'") +
span(v-else) -
@@ -220,14 +220,14 @@ g
span(v-if="varresult !== null") ({{ varresult }})
br
strong
| {{ rightoperand.objectList.map((o: any) => o.lookup[2]).join(", ") }}
| {{ rightoperand?.objectList.map((o: any) => o.lookup[2]).join(", ") }}
span(v-else-if="vardata && vardata.type === 'enum_entry_status'")
span.fa.fa-check-circle-o
| {{ vardata.label }}
span(v-if="varresult !== null") ({{ varresult }})
br
strong
| {{ op.label }} {{ rightoperand }}
| {{ op?.label }} {{ rightoperand }}
g(v-if="result === false", :transform="`translate(${x + boxWidth - 15}, ${y - 10})`")
ellipse(fill="#fff", cx="14.685823", cy="14.318233", rx="12.140151", ry="11.55523")

View File

@@ -201,13 +201,16 @@ footer nav li:not(:first-child):before {
width: 1.5em;
text-align: center;
}
footer nav .btn,
footer nav .btn-link {
display: inline;
padding: 0;
margin: 0;
font-size: 11px;
vertical-align: baseline;
}
footer nav .btn-link {
padding: 0;
}
.js-only {
display: none;

View File

@@ -93,11 +93,11 @@ const showTaxline = computed(() => props.price.rate !== '0.00' && props.price.gr
span(v-if="!freePrice && !originalPrice", v-html="priceline")
span(v-if="!freePrice && originalPrice")
del.pretix-widget-pricebox-original-price(:aria-label="originalPriceAriaLabel", v-html="originalLine")
|
|!{' '}
ins.pretix-widget-pricebox-new-price(:aria-label="newPriceAriaLabel", v-html="priceline")
div(v-if="freePrice")
span.pretix-widget-pricebox-currency(:id="priceBoxId") {{ store.currency }}
|
|!{' '}
input.pretix-widget-pricebox-price-input(
type="number",
placeholder="0",

View File

@@ -212,4 +212,17 @@ def membership_type(organizer):
return organizer.membership_types.create(name='foo')
@pytest.fixture
def clist(event, item):
c = event.checkin_lists.create(name="Default", all_products=False)
c.limit_products.add(item)
return c
@pytest.fixture
def clist_all(event, item):
c = event.checkin_lists.create(name="Default", all_products=True)
return c
utils.setup_databases = scopes_disabled()(utils.setup_databases)

View File

@@ -252,19 +252,6 @@ TEST_HISTORY_RES = {
}
@pytest.fixture
def clist(event, item):
c = event.checkin_lists.create(name="Default", all_products=False)
c.limit_products.add(item)
return c
@pytest.fixture
def clist_all(event, item):
c = event.checkin_lists.create(name="Default", all_products=True)
return c
@pytest.mark.django_db
def test_list_list(token_client, organizer, event, clist, item, subevent, django_assert_num_queries):
res = dict(TEST_LIST_RES)

View File

@@ -1079,3 +1079,18 @@ def test_event_edit_restrictions(client, event, organizer, user, team):
assert _get_and_patch_event_export(user2_client, s2)
assert _get_and_patch_event_export(team1_client, s2)
assert _get_and_patch_event_export(user1_client, s2)
@pytest.mark.django_db
def test_event_checkinlist_patch(user_client, organizer, event, user, event_scheduled_export, clist):
event_scheduled_export.export_identifier = "checkinlistpdf"
event_scheduled_export.save()
resp = user_client.patch(
'/api/v1/organizers/{}/events/{}/scheduled_exports/{}/'.format(organizer.slug, event.slug, event_scheduled_export.id),
data={
"export_form_data": {"list": clist.pk},
},
format='json',
)
assert resp.status_code == 200

View File

@@ -27,7 +27,7 @@ from django.core.cache import cache
from django.test import override_settings
from django.utils import translation
from django_scopes import scopes_disabled
from fakeredis import FakeConnection
from fakeredis import FakeRedisConnection
from xdist.dsession import DSession
from pretix.testutils.mock import get_redis_connection
@@ -97,21 +97,21 @@ def fakeredis_client(monkeypatch):
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': f'redis://127.0.0.1:{redis_port}',
'OPTIONS': {
'connection_class': FakeConnection
'connection_class': FakeRedisConnection
}
},
'redis_session': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': f'redis://127.0.0.1:{redis_port}',
'OPTIONS': {
'connection_class': FakeConnection
'connection_class': FakeRedisConnection
}
},
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': f'redis://127.0.0.1:{redis_port}',
'OPTIONS': {
'connection_class': FakeConnection
'connection_class': FakeRedisConnection
}
},
}

View File

@@ -43,7 +43,7 @@ RES_RULE = {
"limit_products": [],
"limit_variations": [],
"all_payment_methods": True,
"limit_payment_methods": set(),
"limit_payment_methods": [],
}

View File

@@ -834,3 +834,56 @@ def test_ambigious_date_with_region(env, job):
with scopes_disabled():
assert env[2].payments.last().info_data["date"] == "2016-05-03"
@pytest.mark.django_db
def test_event_name_prefix_contains_dash(env, orga_job):
event, user, o1, o2 = env
slugs = ['dummy-2', 'dummy2345']
for slug in slugs:
event = Event.objects.create(
organizer=event.organizer, name=slug.upper(), slug=slug,
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
)
with scopes_disabled():
o1.event = Event.objects.get(slug="dummy2345")
o1.save()
process_banktransfers(orga_job, [{
'payer': 'Karla Kundin',
'reference': f'DUMMY2345-{o1.code}',
'date': '2016-01-26',
'amount': '23.00'
}])
with scopes_disabled():
job = BankImportJob.objects.last()
t = job.transactions.last()
assert t.state == BankTransaction.STATE_VALID
@pytest.mark.xfail
@pytest.mark.django_db
def test_event_name_prefix_multiple_dashes(env, orga_job):
# We decided to ignore the case of multiple events where the event slugs only differ in dashes
# for now. If we change that, switch this test case from xfail to regular test.
event, user, o1, o2 = env
slugs = ['dummy-2', 'dummy--2', 'dummy2345']
for slug in slugs:
event = Event.objects.create(
organizer=event.organizer, name=slug.upper(), slug=slug,
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.paypal'
)
with scopes_disabled():
o1.event = Event.objects.get(slug="dummy-2")
o1.save()
process_banktransfers(orga_job, [{
'payer': 'Karla Kundin',
'reference': f'DUMMY2-{o1.code}',
'date': '2016-01-26',
'amount': '23.00'
}])
with scopes_disabled():
job = BankImportJob.objects.last()
t = job.transactions.last()
assert t.state == BankTransaction.STATE_VALID