From cedf2b321bb6ef39e809b2ee7457f9df95e1d586 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 24 Apr 2026 17:30:33 +0300 Subject: [PATCH 01/31] feat(tickets_v2): add per-product VAT rate and receipt VAT breakdown Products now have a vat_percentage field (Finnish rates: 0%, 10%, 13.5%, 25.5%). Prices remain VAT-inclusive. Receipt emails show a dynamic VAT breakdown instead of the hardcoded "(VAT 0%)" placeholder. The shop product card shows the applicable rate, and the order summary table includes a per-rate VAT breakdown in the footer. The admin product form exposes vatPercentage as a SingleSelect field; changing the rate triggers a new product revision. Co-Authored-By: Claude Sonnet 4.6 --- .../[eventSlug]/products/[productId]/page.tsx | 20 +++++++++++++ .../google-material-symbols/README.md | 1 - .../src/components/tickets/ProductCard.tsx | 3 ++ .../src/components/tickets/ProductsTable.tsx | 30 +++++++++++++++++++ kompassi-v2-frontend/src/services/tickets.ts | 2 ++ kompassi-v2-frontend/src/translations/en.tsx | 7 +++++ kompassi-v2-frontend/src/translations/fi.tsx | 7 +++++ kompassi-v2-frontend/src/translations/sv.tsx | 7 +++++ .../graphql/mutations/create_product.py | 1 + .../graphql/mutations/update_product.py | 1 + kompassi/tickets_v2/graphql/product_full.py | 1 + .../tickets_v2/graphql/product_limited.py | 1 + .../migrations/0008_product_vat_percentage.py | 24 +++++++++++++++ kompassi/tickets_v2/models/order.py | 20 ++++++++++++- kompassi/tickets_v2/models/product.py | 7 +++++ kompassi/tickets_v2/models/receipt.py | 1 + .../optimized_server/models/order.py | 19 ++++++++++-- .../optimized_server/models/product.py | 7 ++++- .../optimized_server/models/sql/get_order.sql | 4 ++- .../models/sql/get_order_with_customer.sql | 4 ++- .../models/sql/list_products.sql | 3 +- .../templates/tickets_v2_cancel_en.eml | 4 ++- .../templates/tickets_v2_cancel_fi.eml | 4 ++- .../templates/tickets_v2_receipt_en.eml | 4 ++- .../templates/tickets_v2_receipt_fi.eml | 4 ++- 25 files changed, 173 insertions(+), 13 deletions(-) create mode 100644 kompassi/tickets_v2/migrations/0008_product_vat_percentage.py diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx index b174d01f9..6bd935950 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx @@ -29,6 +29,7 @@ graphql(` title description price + vatPercentage eticketsPerProduct maxPerOrder } @@ -41,6 +42,7 @@ graphql(` title description price + vatPercentage eticketsPerProduct maxPerOrder availableFrom @@ -183,6 +185,17 @@ export default async function AdminProductDetailPage(props: Props) { decimalPlaces: 2, ...t.clientAttributes.unitPrice, }, + { + slug: "vatPercentage", + type: "SingleSelect", + choices: [ + { slug: "0.00", title: "0%" }, + { slug: "10.00", title: "10%" }, + { slug: "13.50", title: "13.5%" }, + { slug: "25.50", title: "25.5%" }, + ], + ...t.clientAttributes.vatPercentage, + }, { slug: "eticketsPerProduct", type: "NumberField", @@ -294,6 +307,13 @@ export default async function AdminProductDetailPage(props: Props) { getCellContents: (product) => formatMoney(product.price), className: "col-1 align-middle", }, + { + slug: "vatPercentage", + title: t.clientAttributes.vatPercentage.title, + getCellContents: (product) => + t.clientAttributes.vatIncluded(product.vatPercentage), + className: "col-1 align-middle", + }, ]; return ( diff --git a/kompassi-v2-frontend/src/components/google-material-symbols/README.md b/kompassi-v2-frontend/src/components/google-material-symbols/README.md index 9f3440b52..cfa4266db 100644 --- a/kompassi-v2-frontend/src/components/google-material-symbols/README.md +++ b/kompassi-v2-frontend/src/components/google-material-symbols/README.md @@ -16,7 +16,6 @@ Current approach is as follows: 3. Download the SVG 4. Using eg. OpenInNewTab.tsx as a template, make the SVG into a React component - - You may need to tweak the vertical translate to make the icon align with text. The `.material-symbol` class lives in `globals.scss`. diff --git a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx index d7d4d0e26..b5be5afcb 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx @@ -25,6 +25,9 @@ export default function ProductCard({ product, messages: t, children }: Props) {
{formatMoney(product.price)} +
+ {t.clientAttributes.vatIncluded(product.vatPercentage)} +
diff --git a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx index 6480f1bea..05d2007aa 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx @@ -6,6 +6,7 @@ interface Product { title: string; quantity: number; price: string; + vatPercentage: string; } interface Order { @@ -20,6 +21,24 @@ interface Props { compact?: boolean; } +function computeVatBreakdown( + products: Product[], +): { rate: string; vat: string }[] { + const totals = new Map(); + for (const p of products) { + const gross = parseFloat(p.price) * p.quantity; + const prev = totals.get(p.vatPercentage) ?? 0; + totals.set(p.vatPercentage, prev + gross); + } + return Array.from(totals.entries()) + .sort(([a], [b]) => parseFloat(a) - parseFloat(b)) + .map(([rate, gross]) => { + const r = parseFloat(rate); + const vat = (gross * r) / (100 + r); + return { rate, vat: vat.toFixed(2) }; + }); +} + export default function ProductsTable({ order, messages: t, @@ -63,6 +82,8 @@ export default function ProductsTable({ className = "table table-striped " + (className ?? "mb-5"); + const vatBreakdown = computeVatBreakdown(order.products); + return ( @@ -75,6 +96,15 @@ export default function ProductsTable({ {formatMoney(order.totalPrice)} + {vatBreakdown.map(({ rate, vat }) => ( + + + {t.Product.clientAttributes.vatIncluded(rate)} + + + {formatMoney(vat)} + + ))} ); diff --git a/kompassi-v2-frontend/src/services/tickets.ts b/kompassi-v2-frontend/src/services/tickets.ts index 5019557da..fa475d0e6 100644 --- a/kompassi-v2-frontend/src/services/tickets.ts +++ b/kompassi-v2-frontend/src/services/tickets.ts @@ -30,6 +30,7 @@ export interface Product { title: string; description: string; price: string; + vatPercentage: string; maxPerOrder: number; available?: boolean; } @@ -169,6 +170,7 @@ export interface Order { title: string; price: string; quantity: number; + vatPercentage: string; }[]; } diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 03083be4a..5d0db7e4f 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -531,6 +531,13 @@ const translations = { selectedQuotas: "Selected quotas", soldOut: "Sold out", isAvailable: "Availability schedule", + vatPercentage: { + title: "VAT rate", + helpText: + "The VAT rate that applies to this product. Prices are VAT-inclusive.", + }, + vatIncluded: (rate: string) => `incl. ${rate}% VAT`, + vatBreakdown: "VAT breakdown", dragToReorder: "Drag to reorder", newProductQuota: { title: "Quota", diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 26f63472f..f9aadf47e 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -526,6 +526,13 @@ const translations: Translations = { selectedQuotas: "Valitut kiintiöt", soldOut: "Loppuunmyyty", isAvailable: "Saatavuusaika", + vatPercentage: { + title: "ALV-prosentti", + helpText: + "Tähän tuotteeseen sovellettava arvonlisäveroprosentti. Hinnat sisältävät ALV:n.", + }, + vatIncluded: (rate: string) => `sis. ${rate}% ALV`, + vatBreakdown: "ALV-erittely", dragToReorder: "Vedä ja pudota järjestääksesi tuotteita", newProductQuota: { title: "Kiintiö", diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index a77bce865..508de1c9c 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -518,6 +518,13 @@ const translations: Translations = { selectedQuotas: "Valda kvoter", soldOut: "Slutsåld", isAvailable: "Tillgänglighetsschema", + vatPercentage: { + title: "Momssats", + helpText: + "Den momssats som gäller för denna produkt. Priserna inkluderar moms.", + }, + vatIncluded: (rate: string) => `inkl. ${rate}% moms`, + vatBreakdown: "Momsspecifikation", dragToReorder: "Dra för att sortera om", newProductQuota: { title: "Kvot", diff --git a/kompassi/tickets_v2/graphql/mutations/create_product.py b/kompassi/tickets_v2/graphql/mutations/create_product.py index 341881136..2725d2fd1 100644 --- a/kompassi/tickets_v2/graphql/mutations/create_product.py +++ b/kompassi/tickets_v2/graphql/mutations/create_product.py @@ -28,6 +28,7 @@ class Meta: "title", "description", "price", + "vat_percentage", ] diff --git a/kompassi/tickets_v2/graphql/mutations/update_product.py b/kompassi/tickets_v2/graphql/mutations/update_product.py index 00d149b6a..7750f800f 100644 --- a/kompassi/tickets_v2/graphql/mutations/update_product.py +++ b/kompassi/tickets_v2/graphql/mutations/update_product.py @@ -31,6 +31,7 @@ class Meta: "title", "description", "price", + "vat_percentage", "max_per_order", "etickets_per_product", "available_from", diff --git a/kompassi/tickets_v2/graphql/product_full.py b/kompassi/tickets_v2/graphql/product_full.py index 6b66b6c7e..a3041730c 100644 --- a/kompassi/tickets_v2/graphql/product_full.py +++ b/kompassi/tickets_v2/graphql/product_full.py @@ -17,6 +17,7 @@ class Meta: "title", "description", "price", + "vat_percentage", "available_from", "available_until", "max_per_order", diff --git a/kompassi/tickets_v2/graphql/product_limited.py b/kompassi/tickets_v2/graphql/product_limited.py index bb68b2877..9b629802a 100644 --- a/kompassi/tickets_v2/graphql/product_limited.py +++ b/kompassi/tickets_v2/graphql/product_limited.py @@ -20,6 +20,7 @@ class Meta: "title", "description", "price", + "vat_percentage", "available_from", "available_until", "max_per_order", diff --git a/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py b/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py new file mode 100644 index 000000000..952a13198 --- /dev/null +++ b/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py @@ -0,0 +1,24 @@ +# Generated by Django 6.0.3 on 2026-04-24 14:16 + +from decimal import Decimal + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("tickets_v2", "0007_no_receipt_on_cancel"), + ] + + operations = [ + migrations.AddField( + model_name="product", + name="vat_percentage", + field=models.DecimalField( + decimal_places=2, + default=Decimal("0"), + help_text="VAT percentage applied to this product. Prices are inclusive of VAT.", + max_digits=4, + ), + ), + ] diff --git a/kompassi/tickets_v2/models/order.py b/kompassi/tickets_v2/models/order.py index 135edde83..c5859ffaa 100644 --- a/kompassi/tickets_v2/models/order.py +++ b/kompassi/tickets_v2/models/order.py @@ -25,7 +25,7 @@ from kompassi.graphql_api.language import SUPPORTED_LANGUAGES from ..optimized_server.models.enums import PaymentProvider, PaymentStampType, PaymentStatus, RefundType -from ..optimized_server.models.order import OrderProduct +from ..optimized_server.models.order import OrderProduct, VatBreakdownLine from ..optimized_server.utils.formatting import format_order_number from ..optimized_server.utils.uuid7 import uuid7 from ..utils.event_partitions import EventPartitionsMixin @@ -70,6 +70,7 @@ def _get_product(cls, event_id: int | str, product_id: int | str) -> Product: "title", "description", "price", + "vat_percentage", "etickets_per_product", ) } @@ -83,11 +84,27 @@ def products(self) -> list[OrderProduct]: title=product.title, price=product.price, quantity=quantity, + vat_percentage=product.vat_percentage, ) for product_id, quantity in self.product_data.items() # type: ignore if quantity > 0 and (product := self._get_product(self.event_id, product_id)) # type: ignore ] + @cached_property + def vat_breakdown(self) -> list[VatBreakdownLine]: + from collections import defaultdict + + totals: dict[Decimal, Decimal] = defaultdict(Decimal) + for op in self.products: + totals[op.vat_percentage] += op.price * op.quantity + result = [] + for rate in sorted(totals): + gross = totals[rate] + vat = (gross * rate / (100 + rate)).quantize(Decimal("0.01")) + net = gross - vat + result.append(VatBreakdownLine(rate=rate, gross=gross, vat=vat, net=net)) + return result + @cached_property def etickets(self) -> list[Product]: """ @@ -204,6 +221,7 @@ def products(self) -> list[OrderProduct]: title=product.title, price=product.price, quantity=quantity, + vat_percentage=product.vat_percentage, ) for (product_id, quantity) in self.product_data.items() if (product := products_by_id[int(product_id)]) and quantity > 0 diff --git a/kompassi/tickets_v2/models/product.py b/kompassi/tickets_v2/models/product.py index 6a1a30a98..6a7447f56 100644 --- a/kompassi/tickets_v2/models/product.py +++ b/kompassi/tickets_v2/models/product.py @@ -1,5 +1,6 @@ from __future__ import annotations +from decimal import Decimal from pathlib import Path from typing import ClassVar @@ -88,6 +89,12 @@ class Product(models.Model): created_at = models.DateTimeField(auto_now_add=True) price = models.DecimalField(max_digits=10, decimal_places=2) + vat_percentage = models.DecimalField( + max_digits=4, + decimal_places=2, + default=Decimal("0"), + help_text="VAT percentage applied to this product. Prices are inclusive of VAT.", + ) title = models.TextField() description = models.TextField() diff --git a/kompassi/tickets_v2/models/receipt.py b/kompassi/tickets_v2/models/receipt.py index c9dc890ce..c0bcd7c4d 100644 --- a/kompassi/tickets_v2/models/receipt.py +++ b/kompassi/tickets_v2/models/receipt.py @@ -315,6 +315,7 @@ def body(self) -> str: order_number=self.order_number, products=self.products, total_price=self.total_price, + vat_breakdown=self.vat_breakdown, have_etickets=self.have_etickets, is_refund=self.receipt_type == ReceiptType.REFUNDED, first_name=self.first_name, diff --git a/kompassi/tickets_v2/optimized_server/models/order.py b/kompassi/tickets_v2/optimized_server/models/order.py index e0e265eac..57398108e 100644 --- a/kompassi/tickets_v2/optimized_server/models/order.py +++ b/kompassi/tickets_v2/optimized_server/models/order.py @@ -125,6 +125,14 @@ class OrderProduct(pydantic.BaseModel): title: str price: Decimal quantity: int + vat_percentage: Decimal + + +class VatBreakdownLine(pydantic.BaseModel): + rate: Decimal + gross: Decimal + vat: Decimal + net: Decimal class Order(pydantic.BaseModel, populate_by_name=True): @@ -176,8 +184,10 @@ async def get(cls, db: AsyncConnection, event_id: int, order_id: UUID) -> Order order_number = 0 language_ = "" - async for total_, order_number_, language_, title, price, quantity, status_ in cursor: - order_products.append(OrderProduct(title=title, price=price, quantity=quantity)) + async for total_, order_number_, language_, title, price, quantity, vat_percentage, status_ in cursor: + order_products.append( + OrderProduct(title=title, price=price, quantity=quantity, vat_percentage=vat_percentage) + ) total_price, order_number, language, status = total_, order_number_, language_, status_ if not order_products: @@ -228,13 +238,16 @@ async def get(cls, db: AsyncConnection, event_id: int, order_id: UUID) -> OrderW title, price, quantity, + vat_percentage, status_, first_name_, last_name_, email_, phone_, ) in cursor: - order_products.append(OrderProduct(title=title, price=price, quantity=quantity)) + order_products.append( + OrderProduct(title=title, price=price, quantity=quantity, vat_percentage=vat_percentage) + ) total_price, order_number, language, status = total_, order_number_, language_, status_ first_name, last_name, email, phone = first_name_, last_name_, email_, phone_ diff --git a/kompassi/tickets_v2/optimized_server/models/product.py b/kompassi/tickets_v2/optimized_server/models/product.py index b71dafaba..677befa6f 100644 --- a/kompassi/tickets_v2/optimized_server/models/product.py +++ b/kompassi/tickets_v2/optimized_server/models/product.py @@ -19,6 +19,10 @@ class Product(pydantic.BaseModel, populate_by_name=True): validation_alias="maxPerOrder", serialization_alias="maxPerOrder", ) + vat_percentage: Decimal = pydantic.Field( + validation_alias="vatPercentage", + serialization_alias="vatPercentage", + ) available: bool | None list_query: ClassVar[bytes] = (Path(__file__).parent / "sql" / "list_products.sql").read_bytes() @@ -30,7 +34,7 @@ async def get_products(cls, aconn: AsyncConnection, event_id: int) -> list[Self] products = [] async for row in cursor: - id, title, description, price, max_per_order, available = row + id, title, description, price, max_per_order, vat_percentage, available = row products.append( cls( id=id, @@ -38,6 +42,7 @@ async def get_products(cls, aconn: AsyncConnection, event_id: int) -> list[Self] description=description, price=price, max_per_order=max_per_order, + vat_percentage=vat_percentage, available=available, ) ) diff --git a/kompassi/tickets_v2/optimized_server/models/sql/get_order.sql b/kompassi/tickets_v2/optimized_server/models/sql/get_order.sql index ce9724478..8f79bc183 100644 --- a/kompassi/tickets_v2/optimized_server/models/sql/get_order.sql +++ b/kompassi/tickets_v2/optimized_server/models/sql/get_order.sql @@ -5,6 +5,7 @@ select p2.title, p2.price, p2.quantity, + p2.vat_percentage, o.cached_status as status from tickets_v2_order o @@ -12,7 +13,8 @@ from select p.title, p.price, - cast(pd.value as int) as quantity + cast(pd.value as int) as quantity, + p.vat_percentage from tickets_v2_product p join jsonb_each(o.product_data) pd on (cast(pd.key as int) = p.id) diff --git a/kompassi/tickets_v2/optimized_server/models/sql/get_order_with_customer.sql b/kompassi/tickets_v2/optimized_server/models/sql/get_order_with_customer.sql index 9efac7f1c..516536550 100644 --- a/kompassi/tickets_v2/optimized_server/models/sql/get_order_with_customer.sql +++ b/kompassi/tickets_v2/optimized_server/models/sql/get_order_with_customer.sql @@ -5,6 +5,7 @@ select p2.title, p2.price, p2.quantity, + p2.vat_percentage, o.cached_status as status, o.last_name, o.first_name, @@ -16,7 +17,8 @@ from select p.title, p.price, - cast(pd.value as int) as quantity + cast(pd.value as int) as quantity, + p.vat_percentage from tickets_v2_product p join jsonb_each(o.product_data) pd on (cast(pd.key as int) = p.id) diff --git a/kompassi/tickets_v2/optimized_server/models/sql/list_products.sql b/kompassi/tickets_v2/optimized_server/models/sql/list_products.sql index da1dc8e8e..91e687178 100644 --- a/kompassi/tickets_v2/optimized_server/models/sql/list_products.sql +++ b/kompassi/tickets_v2/optimized_server/models/sql/list_products.sql @@ -22,6 +22,7 @@ select p.description, p.price, p.max_per_order, + p.vat_percentage, bool_and(qa.available) as available from tickets_v2_product p @@ -32,5 +33,5 @@ where and p.superseded_by_id is null and p.available_from <= now() and (p.available_until is null or p.available_until > now()) -group by 1, 2, 3, 4, 5 +group by 1, 2, 3, 4, 5, 6 order by p.ordering; diff --git a/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml b/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml index 2a131c3cc..af62f13e2 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml @@ -8,7 +8,9 @@ Contents of the order: {% for op in products %}{{ op.quantity }} pcs {{ op.title }} {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} -Total: {{ total_price|format_money }} (VAT 0%) +Total: {{ total_price|format_money }} (incl. VAT) +{% for vb in vat_breakdown %}VAT {{ vb.rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) +{% endfor %} If you suspect this is in error, please contact us by replying to this message.{% if is_refund %} diff --git a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml index d3e4e3329..50ed89001 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml @@ -7,7 +7,9 @@ Tilaus sisälsi seuraavat tuotteet: {% for op in products %}{{ op.quantity }} kpl {{ op.title }} {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} -Yhteensä: {{ total_price|format_money }} (ALV 0%) +Yhteensä: {{ total_price|format_money }} (sis. ALV) +{% for vb in vat_breakdown %}ALV {{ vb.rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% endfor %} Jos epäilet, että tilauksesi on peruuntunut virheellisesti, ota yhteyttä asiakaspalveluun vastaamalla tähän viestiin.{% if is_refund %} diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml index afa12c139..f835e0417 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml @@ -8,7 +8,9 @@ We confirm the following products have been paid for: {% for op in products %}{{ op.quantity }} pcs {{ op.title }} {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} -Total: {{ total_price|format_money }} (VAT 0%){% if have_etickets %} +Total: {{ total_price|format_money }} (incl. VAT) +{% for vb in vat_breakdown %}VAT {{ vb.rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) +{% endfor %}{% if have_etickets %} Please find attached your electronic tickets. The electronic ticket will be exchanged for a wristband at the ticket exchange when you arrive at the event. diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml index 9dbfdd8ef..7764adf89 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml @@ -8,7 +8,9 @@ Vahvistamme maksetuiksi seuraavat lipputuotteet: {% for op in products %}{{ op.quantity }} kpl {{ op.title }} {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} -Yhteensä: {{ total_price|format_money }} (ALV 0%){% if have_etickets %} +Yhteensä: {{ total_price|format_money }} (sis. ALV) +{% for vb in vat_breakdown %}ALV {{ vb.rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% endfor %}{% if have_etickets %} Löydät tilaamasi sähköiset liput liitetiedostosta. Sähköinen lippu vaihdetaan rannekkeeseen lipunvaihtopisteessä saapuessasi tapahtumaan. Voit From 97b1121e7e49cb63116df5ad8e864d2d56c89040 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 24 Apr 2026 17:40:16 +0300 Subject: [PATCH 02/31] feat(tickets_v2): send items in Paytrail CreatePaymentRequest Adds PaytrailItem model and populates the items array in Paytrail payment requests, enabling per-rate VAT breakdown in Paytrail merchant reports. Each order line becomes one item with unitPrice, units, vatPercentage, and a description (product title). For new orders, the order is fetched back from the DB inside the same transaction to retrieve product details. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/optimized_server/app.py | 5 ++- .../optimized_server/providers/null.py | 3 +- .../optimized_server/providers/paytrail.py | 37 ++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/kompassi/tickets_v2/optimized_server/app.py b/kompassi/tickets_v2/optimized_server/app.py index b997880f3..36199a31c 100644 --- a/kompassi/tickets_v2/optimized_server/app.py +++ b/kompassi/tickets_v2/optimized_server/app.py @@ -104,7 +104,10 @@ async def create_order( try: async with db.transaction(): result = await order.save(db, event.id) - request, request_stamp = provider.prepare_for_new_order(order, result) + fetched_order = await Order.get(db, event.id, result.order_id) + request, request_stamp = provider.prepare_for_new_order( + order, result, fetched_order.products if fetched_order else [] + ) await request_stamp.save(db) except NotEnoughTickets as e: raise HTTPException(409, "NOT_ENOUGH_TICKETS") from e diff --git a/kompassi/tickets_v2/optimized_server/providers/null.py b/kompassi/tickets_v2/optimized_server/providers/null.py index b32b00ad7..b0f720eb2 100644 --- a/kompassi/tickets_v2/optimized_server/providers/null.py +++ b/kompassi/tickets_v2/optimized_server/providers/null.py @@ -9,7 +9,7 @@ if TYPE_CHECKING: from ..models.event import Event - from ..models.order import CreateOrderRequest, CreateOrderResult, OrderWithCustomer + from ..models.order import CreateOrderRequest, CreateOrderResult, OrderProduct, OrderWithCustomer @dataclass @@ -22,6 +22,7 @@ def prepare_for_new_order( self, _order: CreateOrderRequest, result: CreateOrderResult, + _order_products: list[OrderProduct], ) -> tuple[None, PaymentStamp]: if result.total_price != 0: raise ProviderCannot("Null provider cannot handle non-zero price orders") diff --git a/kompassi/tickets_v2/optimized_server/providers/paytrail.py b/kompassi/tickets_v2/optimized_server/providers/paytrail.py index a2d39e90b..5f0404e56 100644 --- a/kompassi/tickets_v2/optimized_server/providers/paytrail.py +++ b/kompassi/tickets_v2/optimized_server/providers/paytrail.py @@ -5,6 +5,7 @@ from collections.abc import Mapping from dataclasses import dataclass from datetime import UTC, datetime +from decimal import Decimal from enum import Enum from typing import Any, ClassVar, Literal, Self from uuid import UUID, uuid4 @@ -19,7 +20,7 @@ from ..models.customer import Customer from ..models.enums import PaymentProvider, PaymentStampType, PaymentStatus from ..models.event import Event -from ..models.order import CreateOrderRequest, CreateOrderResult, Order, OrderWithCustomer +from ..models.order import CreateOrderRequest, CreateOrderResult, Order, OrderProduct, OrderWithCustomer from ..models.payment_stamp import PaymentStamp from ..utils.paytrail_hmac import calculate_hmac @@ -79,6 +80,34 @@ def for_refund_callback(cls, event_slug: str, order_id: UUID) -> CallbackUrls: ) +class PaytrailItem(pydantic.BaseModel): + """ + A line item in a Paytrail payment request. + Including items enables per-rate VAT breakdown in Paytrail reports. + + Docs: https://docs.paytrail.com/#/?id=item + """ + + unit_price: int = pydantic.Field(serialization_alias="unitPrice") + units: int + vat_percentage: Decimal = pydantic.Field(serialization_alias="vatPercentage") + product_code: str = pydantic.Field(serialization_alias="productCode") + description: str + + @classmethod + def from_order_products(cls, order_products: list[OrderProduct]) -> list[PaytrailItem]: + return [ + cls( + unit_price=int(op.price * 100), + units=op.quantity, + vat_percentage=op.vat_percentage, + product_code=str(i + 1), + description=op.title, + ) + for i, op in enumerate(order_products) + ] + + class CreatePaymentResponse(pydantic.BaseModel): transaction_id: str = pydantic.Field( validation_alias="transactionId", @@ -105,6 +134,7 @@ class CreatePaymentRequest(pydantic.BaseModel): currency: Literal["EUR"] = "EUR" language: str customer: Customer + items: list[PaytrailItem] redirect_urls: CallbackUrls = pydantic.Field(serialization_alias="redirectUrls") callback_urls: CallbackUrls | None = pydantic.Field(serialization_alias="callbackUrls") @@ -124,12 +154,14 @@ def from_create_order_request( event: Event, request: CreateOrderRequest, result: CreateOrderResult, + order_products: list[OrderProduct], ) -> CreatePaymentRequest: return cls( reference=result.reference, amount_cents=int(result.total_price * 100), language=request.language, customer=request.customer, + items=PaytrailItem.from_order_products(order_products), redirect_urls=CallbackUrls.for_payment_redirect(event.slug, result.order_id), callback_urls=None if DEBUG else CallbackUrls.for_payment_callback(event.slug, result.order_id), ) @@ -145,6 +177,7 @@ def from_order( amount_cents=int(order.total_price * 100), language=order.language, customer=order.customer, + items=PaytrailItem.from_order_products(order.products), redirect_urls=CallbackUrls.for_payment_redirect(event.slug, order.id), callback_urls=None if DEBUG else CallbackUrls.for_payment_callback(event.slug, order.id), ) @@ -397,6 +430,7 @@ def prepare_for_new_order( self, order: CreateOrderRequest, result: CreateOrderResult, + order_products: list[OrderProduct], ) -> tuple[PreparedCreatePaymentRequest | None, PaymentStamp]: if result.total_price == 0: return None, PaymentStamp.for_zero_price_order( @@ -411,6 +445,7 @@ def prepare_for_new_order( self.event, order, result, + order_products, ).prepare( self.event, result.order_id, From 229ef9c65c7efd7e78dad38bf2b88241895e7d7e Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 24 Apr 2026 17:49:41 +0300 Subject: [PATCH 03/31] fix(tickets_v2): review fixes for VAT branch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add format_vat_rate helper to strip trailing zeros from VAT rate display (25.50 → 25.5, 10.00 → 10). Applied in email templates via template filter and in frontend via parseFloat in translation functions. - Assert Paytrail item sum equals payment amount via model_validator on CreatePaymentRequest, catching mismatches at construction time. - Raise UnsaneSituation instead of silently passing empty items when fetched_order is None after creation in app.py. Co-Authored-By: Claude Sonnet 4.6 --- kompassi-v2-frontend/src/translations/en.tsx | 2 +- kompassi-v2-frontend/src/translations/fi.tsx | 2 +- kompassi-v2-frontend/src/translations/sv.tsx | 2 +- kompassi/tickets_v2/optimized_server/app.py | 8 ++++---- .../optimized_server/providers/paytrail.py | 7 +++++++ .../optimized_server/utils/formatting.py | 16 ++++++++++++++++ .../templates/tickets_v2_cancel_en.eml | 2 +- .../templates/tickets_v2_cancel_fi.eml | 2 +- .../templates/tickets_v2_receipt_en.eml | 2 +- .../templates/tickets_v2_receipt_fi.eml | 2 +- .../tickets_v2/templatetags/tickets_v2_tags.py | 3 ++- 11 files changed, 36 insertions(+), 12 deletions(-) diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 5d0db7e4f..6b409dd8c 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -536,7 +536,7 @@ const translations = { helpText: "The VAT rate that applies to this product. Prices are VAT-inclusive.", }, - vatIncluded: (rate: string) => `incl. ${rate}% VAT`, + vatIncluded: (rate: string) => `incl. ${parseFloat(rate)}% VAT`, vatBreakdown: "VAT breakdown", dragToReorder: "Drag to reorder", newProductQuota: { diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index f9aadf47e..2d426d726 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -531,7 +531,7 @@ const translations: Translations = { helpText: "Tähän tuotteeseen sovellettava arvonlisäveroprosentti. Hinnat sisältävät ALV:n.", }, - vatIncluded: (rate: string) => `sis. ${rate}% ALV`, + vatIncluded: (rate: string) => `sis. ${parseFloat(rate)}% ALV`, vatBreakdown: "ALV-erittely", dragToReorder: "Vedä ja pudota järjestääksesi tuotteita", newProductQuota: { diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 508de1c9c..3dd78c3f2 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -523,7 +523,7 @@ const translations: Translations = { helpText: "Den momssats som gäller för denna produkt. Priserna inkluderar moms.", }, - vatIncluded: (rate: string) => `inkl. ${rate}% moms`, + vatIncluded: (rate: string) => `inkl. ${parseFloat(rate)}% moms`, vatBreakdown: "Momsspecifikation", dragToReorder: "Dra för att sortera om", newProductQuota: { diff --git a/kompassi/tickets_v2/optimized_server/app.py b/kompassi/tickets_v2/optimized_server/app.py index 36199a31c..be4968bbc 100644 --- a/kompassi/tickets_v2/optimized_server/app.py +++ b/kompassi/tickets_v2/optimized_server/app.py @@ -10,7 +10,7 @@ from kompassi.graphql_api.language import DEFAULT_LANGUAGE, getattr_message_in_language from .db import DB, lifespan -from .excs import InvalidProducts, NotEnoughTickets, ProviderCannot +from .excs import InvalidProducts, NotEnoughTickets, ProviderCannot, UnsaneSituation from .models.enums import PaymentStampType from .models.event import Event from .models.order import CreateOrderRequest, Order, OrderWithCustomer @@ -105,9 +105,9 @@ async def create_order( async with db.transaction(): result = await order.save(db, event.id) fetched_order = await Order.get(db, event.id, result.order_id) - request, request_stamp = provider.prepare_for_new_order( - order, result, fetched_order.products if fetched_order else [] - ) + if fetched_order is None: + raise UnsaneSituation("Order not found after creation") + request, request_stamp = provider.prepare_for_new_order(order, result, fetched_order.products) await request_stamp.save(db) except NotEnoughTickets as e: raise HTTPException(409, "NOT_ENOUGH_TICKETS") from e diff --git a/kompassi/tickets_v2/optimized_server/providers/paytrail.py b/kompassi/tickets_v2/optimized_server/providers/paytrail.py index 5f0404e56..e917258f2 100644 --- a/kompassi/tickets_v2/optimized_server/providers/paytrail.py +++ b/kompassi/tickets_v2/optimized_server/providers/paytrail.py @@ -138,6 +138,13 @@ class CreatePaymentRequest(pydantic.BaseModel): redirect_urls: CallbackUrls = pydantic.Field(serialization_alias="redirectUrls") callback_urls: CallbackUrls | None = pydantic.Field(serialization_alias="callbackUrls") + @pydantic.model_validator(mode="after") + def validate_items_sum(self) -> Self: + items_sum = sum(item.unit_price * item.units for item in self.items) + if items_sum != self.amount_cents: + raise ValueError(f"Items sum {items_sum} does not match amount {self.amount_cents}") + return self + @pydantic.field_validator("language", mode="before") @staticmethod def validate_language(value: str): diff --git a/kompassi/tickets_v2/optimized_server/utils/formatting.py b/kompassi/tickets_v2/optimized_server/utils/formatting.py index c7caded45..da4292d8b 100644 --- a/kompassi/tickets_v2/optimized_server/utils/formatting.py +++ b/kompassi/tickets_v2/optimized_server/utils/formatting.py @@ -17,6 +17,22 @@ def format_money(euros: Decimal) -> str: return f"{euros:0.2f} €".replace(".", ",") +def format_vat_rate(rate: Decimal) -> str: + """ + Format a VAT rate for display, stripping unnecessary trailing zeros. + + >>> format_vat_rate(Decimal('25.50')) + '25.5' + >>> format_vat_rate(Decimal('10.00')) + '10' + >>> format_vat_rate(Decimal('0')) + '0' + >>> format_vat_rate(Decimal('13.50')) + '13.5' + """ + return str(rate.normalize()) + + def format_order_number(order_number: int): """ >>> format_order_number(423125) diff --git a/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml b/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml index af62f13e2..cc4f361e5 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_cancel_en.eml @@ -9,7 +9,7 @@ Contents of the order: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Total: {{ total_price|format_money }} (incl. VAT) -{% for vb in vat_breakdown %}VAT {{ vb.rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}VAT {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) {% endfor %} If you suspect this is in error, please contact us by replying to this message.{% if is_refund %} diff --git a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml index 50ed89001..7234d91dd 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml @@ -8,7 +8,7 @@ Tilaus sisälsi seuraavat tuotteet: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Yhteensä: {{ total_price|format_money }} (sis. ALV) -{% for vb in vat_breakdown %}ALV {{ vb.rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) {% endfor %} Jos epäilet, että tilauksesi on peruuntunut virheellisesti, diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml index f835e0417..886ea522d 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml @@ -9,7 +9,7 @@ We confirm the following products have been paid for: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Total: {{ total_price|format_money }} (incl. VAT) -{% for vb in vat_breakdown %}VAT {{ vb.rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}VAT {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (of {{ vb.gross|format_money }}) {% endfor %}{% if have_etickets %} Please find attached your electronic tickets. The electronic ticket will be diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml index 7764adf89..a9e6f0dae 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml @@ -9,7 +9,7 @@ Vahvistamme maksetuiksi seuraavat lipputuotteet: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Yhteensä: {{ total_price|format_money }} (sis. ALV) -{% for vb in vat_breakdown %}ALV {{ vb.rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) {% endfor %}{% if have_etickets %} Löydät tilaamasi sähköiset liput liitetiedostosta. Sähköinen lippu diff --git a/kompassi/tickets_v2/templatetags/tickets_v2_tags.py b/kompassi/tickets_v2/templatetags/tickets_v2_tags.py index 03dd9fe76..8c88b8352 100644 --- a/kompassi/tickets_v2/templatetags/tickets_v2_tags.py +++ b/kompassi/tickets_v2/templatetags/tickets_v2_tags.py @@ -1,7 +1,8 @@ from django.template import Library -from ..optimized_server.utils.formatting import format_money, format_order_number +from ..optimized_server.utils.formatting import format_money, format_order_number, format_vat_rate register = Library() register.filter(format_money) register.filter(format_order_number) +register.filter(format_vat_rate) From 3a6711feca875c080270dca82fa62674a2ad56d6 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 24 Apr 2026 17:55:46 +0300 Subject: [PATCH 04/31] fix(tickets_v2): locale-aware VAT rate formatting format_vat_rate now accepts a language parameter and uses comma as decimal separator for Finnish and Swedish locales (25,5%) while keeping period for English (25.5%). Email templates pass the locale explicitly via filter argument (eg. format_vat_rate:"fi"). On the frontend, a new formatVatRate helper follows the same pattern as formatMoney. ProductCard and ProductsTable accept a locale prop and format the rate before passing it to the vatIncluded translation function, which now receives a pre-formatted string. Also adds missing vatPercentage to GraphQL queries in profile order detail and admin order detail pages. Co-Authored-By: Claude Sonnet 4.6 --- .../[eventSlug]/orders-admin/[orderId]/page.tsx | 2 ++ .../[eventSlug]/orders/[orderId]/page.tsx | 2 +- .../[eventSlug]/products/[productId]/page.tsx | 5 ++++- .../app/[locale]/[eventSlug]/tickets/page.tsx | 1 + .../orders/[eventSlug]/[orderId]/page.tsx | 7 ++++++- .../src/components/tickets/ProductCard.tsx | 13 +++++++++++-- .../src/components/tickets/ProductsTable.tsx | 7 ++++++- .../src/helpers/formatVatRate.ts | 8 ++++++++ kompassi-v2-frontend/src/translations/en.tsx | 3 +-- kompassi-v2-frontend/src/translations/fi.tsx | 2 +- kompassi-v2-frontend/src/translations/sv.tsx | 2 +- .../optimized_server/utils/formatting.py | 16 ++++++++++++---- .../templates/tickets_v2_cancel_fi.eml | 2 +- .../templates/tickets_v2_receipt_fi.eml | 2 +- 14 files changed, 56 insertions(+), 16 deletions(-) create mode 100644 kompassi-v2-frontend/src/helpers/formatVatRate.ts diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/[orderId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/[orderId]/page.tsx index 57820e82c..72a775eed 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/[orderId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/[orderId]/page.tsx @@ -94,6 +94,7 @@ const query = graphql(` title quantity price + vatPercentage } paymentStamps { ...AdminOrderPaymentStamp @@ -542,6 +543,7 @@ export default async function AdminOrderPage(props: Props) { - + {showPayButton && (
diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx index 6bd935950..6eef8fdf2 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx @@ -20,6 +20,7 @@ import SubmitButton from "@/components/forms/SubmitButton"; import ModalButton from "@/components/ModalButton"; import TicketsAdminView from "@/components/tickets/TicketsAdminView"; import formatMoney from "@/helpers/formatMoney"; +import formatVatRate from "@/helpers/formatVatRate"; import getPageTitle from "@/helpers/getPageTitle"; import { getTranslations } from "@/translations"; @@ -311,7 +312,9 @@ export default async function AdminProductDetailPage(props: Props) { slug: "vatPercentage", title: t.clientAttributes.vatPercentage.title, getCellContents: (product) => - t.clientAttributes.vatIncluded(product.vatPercentage), + t.clientAttributes.vatIncluded( + formatVatRate(product.vatPercentage, locale), + ), className: "col-1 align-middle", }, ]; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/tickets/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/tickets/page.tsx index c8d633a41..0b2c86ba5 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/tickets/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/tickets/page.tsx @@ -74,6 +74,7 @@ export default async function TicketsPage(props: Props) { ); diff --git a/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx index 064b52ada..374437c33 100644 --- a/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx @@ -32,6 +32,7 @@ const query = graphql(` title quantity price + vatPercentage } event { @@ -122,7 +123,11 @@ export default async function ProfileOrderPage(props: Props) { event={order.event} /> - + {order.canPay && (
diff --git a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx index b5be5afcb..7bc944dad 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx @@ -3,16 +3,23 @@ import Card from "react-bootstrap/Card"; import CardBody from "react-bootstrap/CardBody"; import CardTitle from "react-bootstrap/CardTitle"; import formatMoney from "@/helpers/formatMoney"; +import formatVatRate from "@/helpers/formatVatRate"; import { Product } from "@/services/tickets"; import { Translations } from "@/translations/en"; interface Props { product: Product; + locale: string; messages: Translations["Tickets"]["Product"]; children?: ReactNode; } -export default function ProductCard({ product, messages: t, children }: Props) { +export default function ProductCard({ + product, + locale, + messages: t, + children, +}: Props) { const className = product.available ? "" : "text-muted"; return ( @@ -26,7 +33,9 @@ export default function ProductCard({ product, messages: t, children }: Props) {
{formatMoney(product.price)}
- {t.clientAttributes.vatIncluded(product.vatPercentage)} + {t.clientAttributes.vatIncluded( + formatVatRate(product.vatPercentage, locale), + )}
diff --git a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx index 05d2007aa..1fd2ae906 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx @@ -1,5 +1,6 @@ import { Column, DataTable } from "../DataTable"; import formatMoney from "@/helpers/formatMoney"; +import formatVatRate from "@/helpers/formatVatRate"; import type { Translations } from "@/translations/en"; interface Product { @@ -16,6 +17,7 @@ interface Order { interface Props { order: Order; + locale: string; messages: Translations["Tickets"]; className?: string; compact?: boolean; @@ -41,6 +43,7 @@ function computeVatBreakdown( export default function ProductsTable({ order, + locale, messages: t, className, compact, @@ -99,7 +102,9 @@ export default function ProductsTable({ {vatBreakdown.map(({ rate, vat }) => ( - {t.Product.clientAttributes.vatIncluded(rate)} + {t.Product.clientAttributes.vatIncluded( + formatVatRate(rate, locale), + )} {formatMoney(vat)} diff --git a/kompassi-v2-frontend/src/helpers/formatVatRate.ts b/kompassi-v2-frontend/src/helpers/formatVatRate.ts new file mode 100644 index 000000000..d38cd57b6 --- /dev/null +++ b/kompassi-v2-frontend/src/helpers/formatVatRate.ts @@ -0,0 +1,8 @@ +export default function formatVatRate(value: string, locale: string = "en") { + const num = parseFloat(value); + const formatted = num.toString(); + if (locale === "fi" || locale === "sv") { + return formatted.replace(".", ","); + } + return formatted; +} diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 6b409dd8c..f720be791 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -1,5 +1,4 @@ import { JSX, ReactNode } from "react"; - const translations = { Common: { ok: "OK", @@ -536,7 +535,7 @@ const translations = { helpText: "The VAT rate that applies to this product. Prices are VAT-inclusive.", }, - vatIncluded: (rate: string) => `incl. ${parseFloat(rate)}% VAT`, + vatIncluded: (rate: string) => `incl. ${rate}% VAT`, vatBreakdown: "VAT breakdown", dragToReorder: "Drag to reorder", newProductQuota: { diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 2d426d726..f9aadf47e 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -531,7 +531,7 @@ const translations: Translations = { helpText: "Tähän tuotteeseen sovellettava arvonlisäveroprosentti. Hinnat sisältävät ALV:n.", }, - vatIncluded: (rate: string) => `sis. ${parseFloat(rate)}% ALV`, + vatIncluded: (rate: string) => `sis. ${rate}% ALV`, vatBreakdown: "ALV-erittely", dragToReorder: "Vedä ja pudota järjestääksesi tuotteita", newProductQuota: { diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 3dd78c3f2..508de1c9c 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -523,7 +523,7 @@ const translations: Translations = { helpText: "Den momssats som gäller för denna produkt. Priserna inkluderar moms.", }, - vatIncluded: (rate: string) => `inkl. ${parseFloat(rate)}% moms`, + vatIncluded: (rate: string) => `inkl. ${rate}% moms`, vatBreakdown: "Momsspecifikation", dragToReorder: "Dra för att sortera om", newProductQuota: { diff --git a/kompassi/tickets_v2/optimized_server/utils/formatting.py b/kompassi/tickets_v2/optimized_server/utils/formatting.py index da4292d8b..0cbb5a0ae 100644 --- a/kompassi/tickets_v2/optimized_server/utils/formatting.py +++ b/kompassi/tickets_v2/optimized_server/utils/formatting.py @@ -17,20 +17,28 @@ def format_money(euros: Decimal) -> str: return f"{euros:0.2f} €".replace(".", ",") -def format_vat_rate(rate: Decimal) -> str: +def format_vat_rate(rate: Decimal, language: str = "en") -> str: """ Format a VAT rate for display, stripping unnecessary trailing zeros. + Uses comma as decimal separator for Finnish and Swedish locales. >>> format_vat_rate(Decimal('25.50')) '25.5' + >>> format_vat_rate(Decimal('25.50'), 'fi') + '25,5' >>> format_vat_rate(Decimal('10.00')) '10' + >>> format_vat_rate(Decimal('10.00'), 'fi') + '10' >>> format_vat_rate(Decimal('0')) '0' - >>> format_vat_rate(Decimal('13.50')) - '13.5' + >>> format_vat_rate(Decimal('13.50'), 'sv') + '13,5' """ - return str(rate.normalize()) + result = str(rate.normalize()) + if language in ("fi", "sv"): + result = result.replace(".", ",") + return result def format_order_number(order_number: int): diff --git a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml index 7234d91dd..ba8223385 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_cancel_fi.eml @@ -8,7 +8,7 @@ Tilaus sisälsi seuraavat tuotteet: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Yhteensä: {{ total_price|format_money }} (sis. ALV) -{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate:"fi" }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) {% endfor %} Jos epäilet, että tilauksesi on peruuntunut virheellisesti, diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml index a9e6f0dae..04c08ccdb 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml @@ -9,7 +9,7 @@ Vahvistamme maksetuiksi seuraavat lipputuotteet: {{ op.quantity }} x {{ op.price|format_money }} {% endfor %} Yhteensä: {{ total_price|format_money }} (sis. ALV) -{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) +{% for vb in vat_breakdown %}ALV {{ vb.rate|format_vat_rate:"fi" }}%: {{ vb.vat|format_money }} (sisältyy summaan {{ vb.gross|format_money }}) {% endfor %}{% if have_etickets %} Löydät tilaamasi sähköiset liput liitetiedostosta. Sähköinen lippu From 947df75f4e2a8df07bf0949fd18acf40590483b9 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 24 Apr 2026 17:56:44 +0300 Subject: [PATCH 05/31] chore: generate frontend types --- kompassi-v2-frontend/src/__generated__/gql.ts | 24 +++++++++--------- .../src/__generated__/graphql.ts | 25 +++++++++++-------- 2 files changed, 27 insertions(+), 22 deletions(-) diff --git a/kompassi-v2-frontend/src/__generated__/gql.ts b/kompassi-v2-frontend/src/__generated__/gql.ts index 0919b9a90..80d7f6ddc 100644 --- a/kompassi-v2-frontend/src/__generated__/gql.ts +++ b/kompassi-v2-frontend/src/__generated__/gql.ts @@ -36,7 +36,7 @@ type Documents = { "\n fragment AdminOrderPaymentStamp on LimitedPaymentStampType {\n id\n createdAt\n correlationId\n provider\n type\n status\n data\n }\n": typeof types.AdminOrderPaymentStampFragmentDoc, "\n fragment AdminOrderReceipt on LimitedReceiptType {\n correlationId\n createdAt\n email\n type\n status\n }\n": typeof types.AdminOrderReceiptFragmentDoc, "\n fragment AdminOrderCode on LimitedCodeType {\n code\n literateCode\n status\n usedOn\n productText\n }\n": typeof types.AdminOrderCodeFragmentDoc, - "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": typeof types.AdminOrderDetailDocument, + "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": typeof types.AdminOrderDetailDocument, "\n mutation AdminCreateOrder($input: CreateOrderInput!) {\n createOrder(input: $input) {\n order {\n event {\n slug\n }\n id\n }\n }\n }\n": typeof types.AdminCreateOrderDocument, "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": typeof types.NewOrderProductFragmentDoc, "\n query NewOrderPage($eventSlug: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n products {\n ...NewOrderProduct\n }\n }\n }\n }\n": typeof types.NewOrderPageDocument, @@ -52,8 +52,8 @@ type Documents = { "\n query PeoplePage(\n $eventSlug: String!\n $filters: [DimensionFilterInput!]\n $locale: String\n $search: String\n $returnNone: Boolean = false\n ) {\n event(slug: $eventSlug) {\n slug\n name\n timezone\n\n involvement {\n dimensions(publicOnly: false) {\n ...DimensionFilter\n ...CachedDimensionsBadges\n ...DimensionValueSelect\n }\n\n people(filters: $filters, search: $search, returnNone: $returnNone) {\n ...InvolvedPerson\n }\n }\n }\n }\n": typeof types.PeoplePageDocument, "\n mutation UpdateProduct($input: UpdateProductInput!) {\n updateProduct(input: $input) {\n product {\n id\n }\n }\n }\n": typeof types.UpdateProductDocument, "\n mutation DeleteProduct($input: DeleteProductInput!) {\n deleteProduct(input: $input) {\n id\n }\n }\n": typeof types.DeleteProductDocument, - "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n }\n": typeof types.AdminProductOldVersionFragmentDoc, - "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n": typeof types.AdminProductDetailFragmentDoc, + "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n }\n": typeof types.AdminProductOldVersionFragmentDoc, + "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n": typeof types.AdminProductDetailFragmentDoc, "\n query AdminProductDetailPage($eventSlug: String!, $productId: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n quotas {\n id\n name\n countTotal\n }\n\n product(id: $productId) {\n ...AdminProductDetail\n }\n }\n }\n }\n": typeof types.AdminProductDetailPageDocument, "\n mutation CreateProduct($input: CreateProductInput!) {\n createProduct(input: $input) {\n product {\n id\n }\n }\n }\n": typeof types.CreateProductDocument, "\n mutation ReorderProducts($input: ReorderProductsInput!) {\n reorderProducts(input: $input) {\n products {\n id\n }\n }\n }\n": typeof types.ReorderProductsDocument, @@ -180,7 +180,7 @@ type Documents = { "\n mutation RevokeKeyPair($id: String!) {\n revokeKeyPair(id: $id) {\n id\n }\n }\n": typeof types.RevokeKeyPairDocument, "\n fragment ProfileEncryptionKeys on KeyPairType {\n id\n createdAt\n }\n": typeof types.ProfileEncryptionKeysFragmentDoc, "\n query ProfileEncryptionKeys {\n profile {\n keypairs {\n ...ProfileEncryptionKeys\n }\n }\n }\n": typeof types.ProfileEncryptionKeysDocument, - "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": typeof types.ProfileOrderDetailDocument, + "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": typeof types.ProfileOrderDetailDocument, "\n mutation ConfirmEmail($input: ConfirmEmailInput!) {\n confirmEmail(input: $input) {\n user {\n email\n }\n }\n }\n": typeof types.ConfirmEmailDocument, "\n fragment ProfileOrder on ProfileOrderType {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n\n event {\n slug\n name\n }\n }\n": typeof types.ProfileOrderFragmentDoc, "\n query ProfileOrders {\n profile {\n tickets {\n orders {\n ...ProfileOrder\n }\n\n haveUnlinkedOrders\n }\n }\n }\n": typeof types.ProfileOrdersDocument, @@ -235,7 +235,7 @@ const documents: Documents = { "\n fragment AdminOrderPaymentStamp on LimitedPaymentStampType {\n id\n createdAt\n correlationId\n provider\n type\n status\n data\n }\n": types.AdminOrderPaymentStampFragmentDoc, "\n fragment AdminOrderReceipt on LimitedReceiptType {\n correlationId\n createdAt\n email\n type\n status\n }\n": types.AdminOrderReceiptFragmentDoc, "\n fragment AdminOrderCode on LimitedCodeType {\n code\n literateCode\n status\n usedOn\n productText\n }\n": types.AdminOrderCodeFragmentDoc, - "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": types.AdminOrderDetailDocument, + "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": types.AdminOrderDetailDocument, "\n mutation AdminCreateOrder($input: CreateOrderInput!) {\n createOrder(input: $input) {\n order {\n event {\n slug\n }\n id\n }\n }\n }\n": types.AdminCreateOrderDocument, "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": types.NewOrderProductFragmentDoc, "\n query NewOrderPage($eventSlug: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n products {\n ...NewOrderProduct\n }\n }\n }\n }\n": types.NewOrderPageDocument, @@ -251,8 +251,8 @@ const documents: Documents = { "\n query PeoplePage(\n $eventSlug: String!\n $filters: [DimensionFilterInput!]\n $locale: String\n $search: String\n $returnNone: Boolean = false\n ) {\n event(slug: $eventSlug) {\n slug\n name\n timezone\n\n involvement {\n dimensions(publicOnly: false) {\n ...DimensionFilter\n ...CachedDimensionsBadges\n ...DimensionValueSelect\n }\n\n people(filters: $filters, search: $search, returnNone: $returnNone) {\n ...InvolvedPerson\n }\n }\n }\n }\n": types.PeoplePageDocument, "\n mutation UpdateProduct($input: UpdateProductInput!) {\n updateProduct(input: $input) {\n product {\n id\n }\n }\n }\n": types.UpdateProductDocument, "\n mutation DeleteProduct($input: DeleteProductInput!) {\n deleteProduct(input: $input) {\n id\n }\n }\n": types.DeleteProductDocument, - "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n }\n": types.AdminProductOldVersionFragmentDoc, - "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n": types.AdminProductDetailFragmentDoc, + "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n }\n": types.AdminProductOldVersionFragmentDoc, + "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n": types.AdminProductDetailFragmentDoc, "\n query AdminProductDetailPage($eventSlug: String!, $productId: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n quotas {\n id\n name\n countTotal\n }\n\n product(id: $productId) {\n ...AdminProductDetail\n }\n }\n }\n }\n": types.AdminProductDetailPageDocument, "\n mutation CreateProduct($input: CreateProductInput!) {\n createProduct(input: $input) {\n product {\n id\n }\n }\n }\n": types.CreateProductDocument, "\n mutation ReorderProducts($input: ReorderProductsInput!) {\n reorderProducts(input: $input) {\n products {\n id\n }\n }\n }\n": types.ReorderProductsDocument, @@ -379,7 +379,7 @@ const documents: Documents = { "\n mutation RevokeKeyPair($id: String!) {\n revokeKeyPair(id: $id) {\n id\n }\n }\n": types.RevokeKeyPairDocument, "\n fragment ProfileEncryptionKeys on KeyPairType {\n id\n createdAt\n }\n": types.ProfileEncryptionKeysFragmentDoc, "\n query ProfileEncryptionKeys {\n profile {\n keypairs {\n ...ProfileEncryptionKeys\n }\n }\n }\n": types.ProfileEncryptionKeysDocument, - "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": types.ProfileOrderDetailDocument, + "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": types.ProfileOrderDetailDocument, "\n mutation ConfirmEmail($input: ConfirmEmailInput!) {\n confirmEmail(input: $input) {\n user {\n email\n }\n }\n }\n": types.ConfirmEmailDocument, "\n fragment ProfileOrder on ProfileOrderType {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n\n event {\n slug\n name\n }\n }\n": types.ProfileOrderFragmentDoc, "\n query ProfileOrders {\n profile {\n tickets {\n orders {\n ...ProfileOrder\n }\n\n haveUnlinkedOrders\n }\n }\n }\n": types.ProfileOrdersDocument, @@ -517,7 +517,7 @@ export function graphql(source: "\n fragment AdminOrderCode on LimitedCodeType /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -581,11 +581,11 @@ export function graphql(source: "\n mutation DeleteProduct($input: DeleteProduc /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n }\n"): (typeof documents)["\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n }\n"]; +export function graphql(source: "\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n }\n"): (typeof documents)["\n fragment AdminProductOldVersion on LimitedProductType {\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n"): (typeof documents)["\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n"]; +export function graphql(source: "\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n"): (typeof documents)["\n fragment AdminProductDetail on FullProductType {\n id\n createdAt\n title\n description\n price\n vatPercentage\n eticketsPerProduct\n maxPerOrder\n availableFrom\n availableUntil\n canDelete\n\n quotas {\n id\n }\n\n supersededBy {\n id\n }\n\n oldVersions {\n ...AdminProductOldVersion\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -1093,7 +1093,7 @@ export function graphql(source: "\n query ProfileEncryptionKeys {\n profile /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/kompassi-v2-frontend/src/__generated__/graphql.ts b/kompassi-v2-frontend/src/__generated__/graphql.ts index 8ec18eed0..c7a63515a 100644 --- a/kompassi-v2-frontend/src/__generated__/graphql.ts +++ b/kompassi-v2-frontend/src/__generated__/graphql.ts @@ -671,6 +671,8 @@ export type FullProductType = { /** The product superseding this product, if any. */ supersededBy?: Maybe; title: Scalars['String']['output']; + /** VAT percentage applied to this product. Prices are inclusive of VAT. */ + vatPercentage: Scalars['Decimal']['output']; }; /** @@ -1216,6 +1218,8 @@ export type LimitedProductType = { price: Scalars['Decimal']['output']; quotas: Array>; title: Scalars['String']['output']; + /** VAT percentage applied to this product. Prices are inclusive of VAT. */ + vatPercentage: Scalars['Decimal']['output']; }; /** Represent Person without a way to traverse back to Event. */ @@ -1951,6 +1955,7 @@ export type OrderProductType = { price: Scalars['Decimal']['output']; quantity: Scalars['Int']['output']; title: Scalars['String']['output']; + vatPercentage: Scalars['Decimal']['output']; }; export type OwnProfileType = { @@ -3065,7 +3070,7 @@ export type AdminOrderDetailQueryVariables = Exact<{ }>; -export type AdminOrderDetailQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', slug: string, name: string, tickets?: { __typename?: 'TicketsV2EventMetaType', order?: { __typename?: 'FullOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, firstName: string, lastName: string, email: string, phone: string, canRefund: boolean, canRefundManually: boolean, canMarkAsPaid: boolean, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any }>, paymentStamps: Array<{ __typename?: 'LimitedPaymentStampType', id: string, createdAt: string, correlationId: string, provider: PaymentProvider, type: PaymentStampType, status: PaymentStatus, data: unknown }>, receipts: Array<{ __typename?: 'LimitedReceiptType', correlationId: string, createdAt: string, email: string, type: ReceiptType, status: ReceiptStatus }>, codes: Array<{ __typename?: 'LimitedCodeType', code: string, literateCode: string, status: CodeStatus, usedOn?: string | null, productText: string }> } | null } | null } | null }; +export type AdminOrderDetailQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', slug: string, name: string, tickets?: { __typename?: 'TicketsV2EventMetaType', order?: { __typename?: 'FullOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, firstName: string, lastName: string, email: string, phone: string, canRefund: boolean, canRefundManually: boolean, canMarkAsPaid: boolean, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any, vatPercentage: any }>, paymentStamps: Array<{ __typename?: 'LimitedPaymentStampType', id: string, createdAt: string, correlationId: string, provider: PaymentProvider, type: PaymentStampType, status: PaymentStatus, data: unknown }>, receipts: Array<{ __typename?: 'LimitedReceiptType', correlationId: string, createdAt: string, email: string, type: ReceiptType, status: ReceiptStatus }>, codes: Array<{ __typename?: 'LimitedCodeType', code: string, literateCode: string, status: CodeStatus, usedOn?: string | null, productText: string }> } | null } | null } | null }; export type AdminCreateOrderMutationVariables = Exact<{ input: CreateOrderInput; @@ -3146,9 +3151,9 @@ export type DeleteProductMutationVariables = Exact<{ export type DeleteProductMutation = { __typename?: 'Mutation', deleteProduct?: { __typename?: 'DeleteProduct', id: string } | null }; -export type AdminProductOldVersionFragment = { __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, eticketsPerProduct: number, maxPerOrder: number }; +export type AdminProductOldVersionFragment = { __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, vatPercentage: any, eticketsPerProduct: number, maxPerOrder: number }; -export type AdminProductDetailFragment = { __typename?: 'FullProductType', id: number, createdAt: string, title: string, description: string, price: any, eticketsPerProduct: number, maxPerOrder: number, availableFrom?: string | null, availableUntil?: string | null, canDelete: boolean, quotas: Array<{ __typename?: 'LimitedQuotaType', id: string }>, supersededBy?: { __typename?: 'LimitedProductType', id: number } | null, oldVersions: Array<{ __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, eticketsPerProduct: number, maxPerOrder: number }> }; +export type AdminProductDetailFragment = { __typename?: 'FullProductType', id: number, createdAt: string, title: string, description: string, price: any, vatPercentage: any, eticketsPerProduct: number, maxPerOrder: number, availableFrom?: string | null, availableUntil?: string | null, canDelete: boolean, quotas: Array<{ __typename?: 'LimitedQuotaType', id: string }>, supersededBy?: { __typename?: 'LimitedProductType', id: number } | null, oldVersions: Array<{ __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, vatPercentage: any, eticketsPerProduct: number, maxPerOrder: number }> }; export type AdminProductDetailPageQueryVariables = Exact<{ eventSlug: Scalars['String']['input']; @@ -3156,7 +3161,7 @@ export type AdminProductDetailPageQueryVariables = Exact<{ }>; -export type AdminProductDetailPageQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', name: string, slug: string, tickets?: { __typename?: 'TicketsV2EventMetaType', quotas: Array<{ __typename?: 'FullQuotaType', id: string, name: string, countTotal: number }>, product: { __typename?: 'FullProductType', id: number, createdAt: string, title: string, description: string, price: any, eticketsPerProduct: number, maxPerOrder: number, availableFrom?: string | null, availableUntil?: string | null, canDelete: boolean, quotas: Array<{ __typename?: 'LimitedQuotaType', id: string }>, supersededBy?: { __typename?: 'LimitedProductType', id: number } | null, oldVersions: Array<{ __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, eticketsPerProduct: number, maxPerOrder: number }> } } | null } | null }; +export type AdminProductDetailPageQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', name: string, slug: string, tickets?: { __typename?: 'TicketsV2EventMetaType', quotas: Array<{ __typename?: 'FullQuotaType', id: string, name: string, countTotal: number }>, product: { __typename?: 'FullProductType', id: number, createdAt: string, title: string, description: string, price: any, vatPercentage: any, eticketsPerProduct: number, maxPerOrder: number, availableFrom?: string | null, availableUntil?: string | null, canDelete: boolean, quotas: Array<{ __typename?: 'LimitedQuotaType', id: string }>, supersededBy?: { __typename?: 'LimitedProductType', id: number } | null, oldVersions: Array<{ __typename?: 'LimitedProductType', createdAt: string, title: string, description: string, price: any, vatPercentage: any, eticketsPerProduct: number, maxPerOrder: number }> } } | null } | null }; export type CreateProductMutationVariables = Exact<{ input: CreateProductInput; @@ -3958,7 +3963,7 @@ export type ProfileOrderDetailQueryVariables = Exact<{ }>; -export type ProfileOrderDetailQuery = { __typename?: 'Query', profile?: { __typename?: 'OwnProfileType', tickets: { __typename?: 'TicketsV2ProfileMetaType', order?: { __typename?: 'ProfileOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, canPay: boolean, canCancel: boolean, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any }>, event: { __typename?: 'LimitedEventType', slug: string, name: string } } | null } } | null }; +export type ProfileOrderDetailQuery = { __typename?: 'Query', profile?: { __typename?: 'OwnProfileType', tickets: { __typename?: 'TicketsV2ProfileMetaType', order?: { __typename?: 'ProfileOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, canPay: boolean, canCancel: boolean, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any, vatPercentage: any }>, event: { __typename?: 'LimitedEventType', slug: string, name: string } } | null } } | null }; export type ConfirmEmailMutationVariables = Exact<{ input: ConfirmEmailInput; @@ -4075,8 +4080,8 @@ export const InvolvedPersonDetailInvolvementFragmentDoc = {"kind":"Document","de export const InvolvedPersonDetailFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileWithInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"profileFieldSelector"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullProfileFieldSelector"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"involvements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPersonDetailInvolvement"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullProfileFieldSelector"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileFieldSelectorType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonDetailInvolvement"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"adminLink"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"cachedAnnotations"}}]}}]} as unknown as DocumentNode; export const InvolvedPersonInvolvementFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonInvolvement"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"adminLink"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"cachedAnnotations"}}]}}]} as unknown as DocumentNode; export const InvolvedPersonFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPerson"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileWithInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"involvements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPersonInvolvement"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonInvolvement"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"adminLink"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"cachedAnnotations"}}]}}]} as unknown as DocumentNode; -export const AdminProductOldVersionFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; -export const AdminProductDetailFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"}},{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"supersededBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oldVersions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductOldVersion"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; +export const AdminProductOldVersionFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; +export const AdminProductDetailFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"}},{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"supersededBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oldVersions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductOldVersion"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; export const ProductListFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductList"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}}]}}]} as unknown as DocumentNode; export const ProgramAdminDetailHostFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminDetailHost"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProgramHostType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"programHostRole"}},{"kind":"Field","name":{"kind":"Name","value":"person"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}}]}}]}}]} as unknown as DocumentNode; export const ProgramAdminDetailInvitationFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProgramAdminDetailInvitation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvitationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}}]}}]} as unknown as DocumentNode; @@ -4145,7 +4150,7 @@ export const ResendOrderConfirmationDocument = {"kind":"Document","definitions": export const UpdateOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateOrderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const CancelAndRefundOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelAndRefundOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CancelAndRefundOrderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelAndRefundOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const MarkOrderAsPaidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkOrderAsPaid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkOrderAsPaidInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markOrderAsPaid"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const AdminOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phone"}},{"kind":"Field","name":{"kind":"Name","value":"canRefund"}},{"kind":"Field","name":{"kind":"Name","value":"canRefundManually"}},{"kind":"Field","name":{"kind":"Name","value":"canMarkAsPaid"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"paymentStamps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderPaymentStamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"receipts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderReceipt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"codes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderCode"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderPaymentStamp"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedPaymentStampType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderReceipt"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedReceiptType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderCode"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedCodeType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"literateCode"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"usedOn"}},{"kind":"Field","name":{"kind":"Name","value":"productText"}}]}}]} as unknown as DocumentNode; +export const AdminOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phone"}},{"kind":"Field","name":{"kind":"Name","value":"canRefund"}},{"kind":"Field","name":{"kind":"Name","value":"canRefundManually"}},{"kind":"Field","name":{"kind":"Name","value":"canMarkAsPaid"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"paymentStamps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderPaymentStamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"receipts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderReceipt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"codes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderCode"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderPaymentStamp"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedPaymentStampType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderReceipt"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedReceiptType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderCode"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedCodeType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"literateCode"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"usedOn"}},{"kind":"Field","name":{"kind":"Name","value":"productText"}}]}}]} as unknown as DocumentNode; export const AdminCreateOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AdminCreateOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOrderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const NewOrderPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NewOrderPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NewOrderProduct"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NewOrderProduct"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; export const AdminOrderListWithOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminOrderListWithOrders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionFilterInput"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProductChoice"}}]}},{"kind":"Field","name":{"kind":"Name","value":"orders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}},{"kind":"Argument","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}},{"kind":"Argument","name":{"kind":"Name","value":"returnNone"},"value":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"OrderList"}}]}},{"kind":"Field","name":{"kind":"Name","value":"countTotalOrders"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductChoice"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"OrderList"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullOrderType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode; @@ -4154,7 +4159,7 @@ export const PersonPageDocument = {"kind":"Document","definitions":[{"kind":"Ope export const PeoplePageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PeoplePage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionFilterInput"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}},{"kind":"Field","name":{"kind":"Name","value":"involvement"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"publicOnly"},"value":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionFilter"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"CachedDimensionsBadges"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionValueSelect"}}]}},{"kind":"Field","name":{"kind":"Name","value":"people"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}},{"kind":"Argument","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}},{"kind":"Argument","name":{"kind":"Name","value":"returnNone"},"value":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPerson"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionFilterValue"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionValueType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonInvolvement"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"adminLink"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"cachedAnnotations"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionFilter"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"isListFilter"}},{"kind":"Field","name":{"kind":"Name","value":"isKeyDimension"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionFilterValue"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CachedDimensionsBadges"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionValueSelect"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPerson"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileWithInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"involvements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPersonInvolvement"}}]}}]}}]} as unknown as DocumentNode; export const UpdateProductDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateProduct"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateProductInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateProduct"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const DeleteProductDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteProduct"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DeleteProductInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteProduct"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; -export const AdminProductDetailPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminProductDetailPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"productId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"countTotal"}}]}},{"kind":"Field","name":{"kind":"Name","value":"product"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"productId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductDetail"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"}},{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"supersededBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oldVersions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductOldVersion"}}]}}]}}]} as unknown as DocumentNode; +export const AdminProductDetailPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminProductDetailPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"productId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"countTotal"}}]}},{"kind":"Field","name":{"kind":"Name","value":"product"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"productId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductDetail"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductOldVersion"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminProductDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsPerProduct"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"canDelete"}},{"kind":"Field","name":{"kind":"Name","value":"quotas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"supersededBy"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oldVersions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminProductOldVersion"}}]}}]}}]} as unknown as DocumentNode; export const CreateProductDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateProduct"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateProductInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createProduct"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"product"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const ReorderProductsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ReorderProducts"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ReorderProductsInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"reorderProducts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const ProductListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProductList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProductList"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductList"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}}]}}]} as unknown as DocumentNode; @@ -4251,7 +4256,7 @@ export const TicketsAdminReportsPageDocument = {"kind":"Document","definitions": export const GenerateKeyPairDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"GenerateKeyPair"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"password"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"generateKeyPair"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"password"},"value":{"kind":"Variable","name":{"kind":"Name","value":"password"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const RevokeKeyPairDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeKeyPair"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"revokeKeyPair"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const ProfileEncryptionKeysDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileEncryptionKeys"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"keypairs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileEncryptionKeys"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileEncryptionKeys"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"KeyPairType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const ProfileOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"eventSlug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}}]}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const ProfileOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"eventSlug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ConfirmEmailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ConfirmEmail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConfirmEmailInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"confirmEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}}]}}]}}]}}]} as unknown as DocumentNode; export const ProfileOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileOrder"}}]}},{"kind":"Field","name":{"kind":"Name","value":"haveUnlinkedOrders"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileOrder"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileOrderType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const ProfileProgramItemListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileProgramItemList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"programs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userRelation"},"value":{"kind":"EnumValue","value":"HOSTING"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileProgramItem"}}]}},{"kind":"Field","name":{"kind":"Name","value":"programOffers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"dimension"},"value":{"kind":"StringValue","value":"state","block":false}},{"kind":"ObjectField","name":{"kind":"Name","value":"values"},"value":{"kind":"StringValue","value":"new","block":false}}]}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileResponsesTableRow"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileProgramItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProgramType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}}]}},{"kind":"Field","name":{"kind":"Name","value":"scheduleItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"startTime"}},{"kind":"Field","name":{"kind":"Name","value":"endTime"}},{"kind":"Field","name":{"kind":"Name","value":"durationMinutes"}},{"kind":"Field","name":{"kind":"Name","value":"location"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileResponsesTableRow"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileResponseType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"revisionCreatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"canEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"mode"},"value":{"kind":"EnumValue","value":"OWNER"}}]},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"keyFieldsOnly"},"value":{"kind":"BooleanValue","value":true}}]},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"keyDimensionsOnly"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}]}},{"kind":"Field","name":{"kind":"Name","value":"value"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"form"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; From 40f9e90964372cd5ea1d8c944a596260b071198a Mon Sep 17 00:00:00 2001 From: Anssi Kolehmainen Date: Fri, 24 Apr 2026 18:51:33 +0300 Subject: [PATCH 06/31] fix: move vatIncluded from clientAttributes to serverAttributes vatIncluded is a function that cannot be serialized across the server/client boundary. Moving it to serverAttributes prevents the 'Functions cannot be passed directly to Client Components' error on the /products page. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/app/[locale]/[eventSlug]/products/[productId]/page.tsx | 2 +- kompassi-v2-frontend/src/components/tickets/ProductCard.tsx | 2 +- kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx | 2 +- kompassi-v2-frontend/src/translations/en.tsx | 2 +- kompassi-v2-frontend/src/translations/fi.tsx | 2 +- kompassi-v2-frontend/src/translations/sv.tsx | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx index 6eef8fdf2..df130799d 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx @@ -312,7 +312,7 @@ export default async function AdminProductDetailPage(props: Props) { slug: "vatPercentage", title: t.clientAttributes.vatPercentage.title, getCellContents: (product) => - t.clientAttributes.vatIncluded( + t.serverAttributes.vatIncluded( formatVatRate(product.vatPercentage, locale), ), className: "col-1 align-middle", diff --git a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx index 7bc944dad..10c73fcdb 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductCard.tsx @@ -33,7 +33,7 @@ export default function ProductCard({
{formatMoney(product.price)}
- {t.clientAttributes.vatIncluded( + {t.serverAttributes.vatIncluded( formatVatRate(product.vatPercentage, locale), )}
diff --git a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx index 1fd2ae906..6af70364e 100644 --- a/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx +++ b/kompassi-v2-frontend/src/components/tickets/ProductsTable.tsx @@ -102,7 +102,7 @@ export default function ProductsTable({ {vatBreakdown.map(({ rate, vat }) => ( - {t.Product.clientAttributes.vatIncluded( + {t.Product.serverAttributes.vatIncluded( formatVatRate(rate, locale), )} diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index f720be791..69f0409bc 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -535,7 +535,6 @@ const translations = { helpText: "The VAT rate that applies to this product. Prices are VAT-inclusive.", }, - vatIncluded: (rate: string) => `incl. ${rate}% VAT`, vatBreakdown: "VAT breakdown", dragToReorder: "Drag to reorder", newProductQuota: { @@ -545,6 +544,7 @@ const translations = { }, }, serverAttributes: { + vatIncluded: (rate: string) => `incl. ${rate}% VAT`, isAvailable: { untilFurtherNotice: "Available until further notice", untilTime: (formattedTime: string) => diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index f9aadf47e..30f3dbe6f 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -531,7 +531,6 @@ const translations: Translations = { helpText: "Tähän tuotteeseen sovellettava arvonlisäveroprosentti. Hinnat sisältävät ALV:n.", }, - vatIncluded: (rate: string) => `sis. ${rate}% ALV`, vatBreakdown: "ALV-erittely", dragToReorder: "Vedä ja pudota järjestääksesi tuotteita", newProductQuota: { @@ -541,6 +540,7 @@ const translations: Translations = { }, }, serverAttributes: { + vatIncluded: (rate: string) => `sis. ${rate}% ALV`, isAvailable: { untilFurtherNotice: "Saatavilla toistaiseksi", untilTime: (formattedTime: string) => diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 508de1c9c..b34c8ab44 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -523,7 +523,6 @@ const translations: Translations = { helpText: "Den momssats som gäller för denna produkt. Priserna inkluderar moms.", }, - vatIncluded: (rate: string) => `inkl. ${rate}% moms`, vatBreakdown: "Momsspecifikation", dragToReorder: "Dra för att sortera om", newProductQuota: { @@ -533,6 +532,7 @@ const translations: Translations = { }, }, serverAttributes: { + vatIncluded: (rate: string) => `inkl. ${rate}% moms`, isAvailable: { untilFurtherNotice: "Tillgänglig tills vidare", untilTime: (formattedTime: string) => From 22b5f16087443841cb7a7c89053cd71ba8d2265c Mon Sep 17 00:00:00 2001 From: Anssi Kolehmainen Date: Fri, 24 Apr 2026 18:54:33 +0300 Subject: [PATCH 07/31] fix: add VAT percentage field to new product form The CreateProductForm backend requires vat_percentage but the frontend new product modal was missing this field, causing a validation error. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../src/app/[locale]/[eventSlug]/products/page.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx index 5a2614087..42dd56a73 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx @@ -183,6 +183,17 @@ export default async function ProductsPage(props: Props) { decimalPlaces: 2, ...t.clientAttributes.unitPrice, }, + { + slug: "vatPercentage", + type: "SingleSelect", + choices: [ + { slug: "0.00", title: "0%" }, + { slug: "10.00", title: "10%" }, + { slug: "13.50", title: "13.5%" }, + { slug: "25.50", title: "25.5%" }, + ], + ...t.clientAttributes.vatPercentage, + }, { slug: "quota", type: "NumberField", From b8ba12d01f148c729b9883c25182afeff47d1ba3 Mon Sep 17 00:00:00 2001 From: Anssi Kolehmainen Date: Fri, 24 Apr 2026 18:56:38 +0300 Subject: [PATCH 08/31] fix: apply camel_case_keys_to_snake_case in CreateProduct mutation The CreateProduct mutation was passing form_data directly to the Django form without converting camelCase keys (e.g. vatPercentage) to snake_case (vat_percentage), causing validation to fail. The UpdateProduct mutation already did this conversion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- kompassi/tickets_v2/graphql/mutations/create_product.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kompassi/tickets_v2/graphql/mutations/create_product.py b/kompassi/tickets_v2/graphql/mutations/create_product.py index 2725d2fd1..dba911c73 100644 --- a/kompassi/tickets_v2/graphql/mutations/create_product.py +++ b/kompassi/tickets_v2/graphql/mutations/create_product.py @@ -6,6 +6,7 @@ from kompassi.access.cbac import graphql_check_model from kompassi.core.models import Event +from kompassi.core.utils.form_utils import camel_case_keys_to_snake_case from kompassi.event_log_v2.utils.emit import emit from ...models.product import Product @@ -49,7 +50,7 @@ def mutate( event = Event.objects.get(slug=input.event_slug) graphql_check_model(Product, event.scope, info, operation="create") - form = CreateProductForm(data=input.form_data) # type: ignore + form = CreateProductForm(data=camel_case_keys_to_snake_case(input.form_data)) # type: ignore if not form.is_valid(): raise ValueError(form.errors) From 202d8bd30022fc98deda87d1a103e972156eabef Mon Sep 17 00:00:00 2001 From: Anssi Kolehmainen Date: Fri, 24 Apr 2026 19:05:05 +0300 Subject: [PATCH 09/31] fix: serialize PaytrailItem vatPercentage as JSON number Paytrail API requires vatPercentage to be a number, but Pydantic v2 serializes Decimal as a string in JSON mode. Changing the type to float ensures correct JSON serialization. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- kompassi/tickets_v2/optimized_server/providers/paytrail.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kompassi/tickets_v2/optimized_server/providers/paytrail.py b/kompassi/tickets_v2/optimized_server/providers/paytrail.py index e917258f2..1a8209377 100644 --- a/kompassi/tickets_v2/optimized_server/providers/paytrail.py +++ b/kompassi/tickets_v2/optimized_server/providers/paytrail.py @@ -5,7 +5,6 @@ from collections.abc import Mapping from dataclasses import dataclass from datetime import UTC, datetime -from decimal import Decimal from enum import Enum from typing import Any, ClassVar, Literal, Self from uuid import UUID, uuid4 @@ -90,7 +89,7 @@ class PaytrailItem(pydantic.BaseModel): unit_price: int = pydantic.Field(serialization_alias="unitPrice") units: int - vat_percentage: Decimal = pydantic.Field(serialization_alias="vatPercentage") + vat_percentage: float = pydantic.Field(serialization_alias="vatPercentage") product_code: str = pydantic.Field(serialization_alias="productCode") description: str From 754dd69859739def0c5d15a2e54b6bed7335a378 Mon Sep 17 00:00:00 2001 From: Anssi Kolehmainen Date: Fri, 24 Apr 2026 19:38:34 +0300 Subject: [PATCH 10/31] fix: add serialization alias for OrderProduct.vat_percentage The order API serializes with by_alias=True, but OrderProduct was missing the vatPercentage alias. The frontend received vat_percentage (snake_case) which didn't match its vatPercentage interface, causing NaN% VAT display and duplicate React keys. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- kompassi/tickets_v2/optimized_server/models/order.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kompassi/tickets_v2/optimized_server/models/order.py b/kompassi/tickets_v2/optimized_server/models/order.py index 57398108e..120985ecb 100644 --- a/kompassi/tickets_v2/optimized_server/models/order.py +++ b/kompassi/tickets_v2/optimized_server/models/order.py @@ -125,7 +125,7 @@ class OrderProduct(pydantic.BaseModel): title: str price: Decimal quantity: int - vat_percentage: Decimal + vat_percentage: Decimal = pydantic.Field(serialization_alias="vatPercentage") class VatBreakdownLine(pydantic.BaseModel): From 14c158930e8fa0c2869795117a5aa3dc280fb02d Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:19:58 +0300 Subject: [PATCH 11/31] fix: make vatPercentage required on add product form Co-Authored-By: Claude Sonnet 4.6 --- .../src/app/[locale]/[eventSlug]/products/page.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx index 42dd56a73..67d86fd8d 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/page.tsx @@ -186,6 +186,7 @@ export default async function ProductsPage(props: Props) { { slug: "vatPercentage", type: "SingleSelect", + required: true, choices: [ { slug: "0.00", title: "0%" }, { slug: "10.00", title: "10%" }, From ac1d3bff3c6254f393b61b7c36d84f6da69f0a95 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:31:57 +0300 Subject: [PATCH 12/31] fix: add vatPercentage and locale to ProductCard in new order page Co-Authored-By: Claude Sonnet 4.6 --- kompassi-v2-frontend/src/__generated__/gql.ts | 6 +++--- kompassi-v2-frontend/src/__generated__/graphql.ts | 8 ++++---- .../app/[locale]/[eventSlug]/orders-admin/new/page.tsx | 8 +++++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/kompassi-v2-frontend/src/__generated__/gql.ts b/kompassi-v2-frontend/src/__generated__/gql.ts index 80d7f6ddc..6d190478f 100644 --- a/kompassi-v2-frontend/src/__generated__/gql.ts +++ b/kompassi-v2-frontend/src/__generated__/gql.ts @@ -38,7 +38,7 @@ type Documents = { "\n fragment AdminOrderCode on LimitedCodeType {\n code\n literateCode\n status\n usedOn\n productText\n }\n": typeof types.AdminOrderCodeFragmentDoc, "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": typeof types.AdminOrderDetailDocument, "\n mutation AdminCreateOrder($input: CreateOrderInput!) {\n createOrder(input: $input) {\n order {\n event {\n slug\n }\n id\n }\n }\n }\n": typeof types.AdminCreateOrderDocument, - "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": typeof types.NewOrderProductFragmentDoc, + "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n vatPercentage\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": typeof types.NewOrderProductFragmentDoc, "\n query NewOrderPage($eventSlug: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n products {\n ...NewOrderProduct\n }\n }\n }\n }\n": typeof types.NewOrderPageDocument, "\n fragment OrderList on FullOrderType {\n id\n formattedOrderNumber\n displayName\n email\n createdAt\n totalPrice\n status\n }\n": typeof types.OrderListFragmentDoc, "\n fragment ProductChoice on FullProductType {\n id\n title\n }\n": typeof types.ProductChoiceFragmentDoc, @@ -237,7 +237,7 @@ const documents: Documents = { "\n fragment AdminOrderCode on LimitedCodeType {\n code\n literateCode\n status\n usedOn\n productText\n }\n": types.AdminOrderCodeFragmentDoc, "\n query AdminOrderDetail($eventSlug: String!, $orderId: String!) {\n event(slug: $eventSlug) {\n slug\n name\n\n tickets {\n order(id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n firstName\n lastName\n email\n phone\n canRefund\n canRefundManually\n canMarkAsPaid\n products {\n title\n quantity\n price\n vatPercentage\n }\n paymentStamps {\n ...AdminOrderPaymentStamp\n }\n receipts {\n ...AdminOrderReceipt\n }\n codes {\n ...AdminOrderCode\n }\n }\n }\n }\n }\n": types.AdminOrderDetailDocument, "\n mutation AdminCreateOrder($input: CreateOrderInput!) {\n createOrder(input: $input) {\n order {\n event {\n slug\n }\n id\n }\n }\n }\n": types.AdminCreateOrderDocument, - "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": types.NewOrderProductFragmentDoc, + "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n vatPercentage\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n": types.NewOrderProductFragmentDoc, "\n query NewOrderPage($eventSlug: String!) {\n event(slug: $eventSlug) {\n name\n slug\n\n tickets {\n products {\n ...NewOrderProduct\n }\n }\n }\n }\n": types.NewOrderPageDocument, "\n fragment OrderList on FullOrderType {\n id\n formattedOrderNumber\n displayName\n email\n createdAt\n totalPrice\n status\n }\n": types.OrderListFragmentDoc, "\n fragment ProductChoice on FullProductType {\n id\n title\n }\n": types.ProductChoiceFragmentDoc, @@ -525,7 +525,7 @@ export function graphql(source: "\n mutation AdminCreateOrder($input: CreateOrd /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n"): (typeof documents)["\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n"]; +export function graphql(source: "\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n vatPercentage\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n"): (typeof documents)["\n fragment NewOrderProduct on FullProductType {\n id\n title\n description\n price\n vatPercentage\n isAvailable\n availableFrom\n availableUntil\n countPaid\n countReserved\n countAvailable\n maxPerOrder\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/kompassi-v2-frontend/src/__generated__/graphql.ts b/kompassi-v2-frontend/src/__generated__/graphql.ts index c7a63515a..fb59265c5 100644 --- a/kompassi-v2-frontend/src/__generated__/graphql.ts +++ b/kompassi-v2-frontend/src/__generated__/graphql.ts @@ -3079,14 +3079,14 @@ export type AdminCreateOrderMutationVariables = Exact<{ export type AdminCreateOrderMutation = { __typename?: 'Mutation', createOrder?: { __typename?: 'CreateOrder', order?: { __typename?: 'FullOrderType', id: string, event: { __typename?: 'LimitedEventType', slug: string } } | null } | null }; -export type NewOrderProductFragment = { __typename?: 'FullProductType', id: number, title: string, description: string, price: any, isAvailable: boolean, availableFrom?: string | null, availableUntil?: string | null, countPaid: number, countReserved: number, countAvailable?: number | null, maxPerOrder: number }; +export type NewOrderProductFragment = { __typename?: 'FullProductType', id: number, title: string, description: string, price: any, vatPercentage: any, isAvailable: boolean, availableFrom?: string | null, availableUntil?: string | null, countPaid: number, countReserved: number, countAvailable?: number | null, maxPerOrder: number }; export type NewOrderPageQueryVariables = Exact<{ eventSlug: Scalars['String']['input']; }>; -export type NewOrderPageQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', name: string, slug: string, tickets?: { __typename?: 'TicketsV2EventMetaType', products: Array<{ __typename?: 'FullProductType', id: number, title: string, description: string, price: any, isAvailable: boolean, availableFrom?: string | null, availableUntil?: string | null, countPaid: number, countReserved: number, countAvailable?: number | null, maxPerOrder: number }> } | null } | null }; +export type NewOrderPageQuery = { __typename?: 'Query', event?: { __typename?: 'FullEventType', name: string, slug: string, tickets?: { __typename?: 'TicketsV2EventMetaType', products: Array<{ __typename?: 'FullProductType', id: number, title: string, description: string, price: any, vatPercentage: any, isAvailable: boolean, availableFrom?: string | null, availableUntil?: string | null, countPaid: number, countReserved: number, countAvailable?: number | null, maxPerOrder: number }> } | null } | null }; export type OrderListFragment = { __typename?: 'FullOrderType', id: string, formattedOrderNumber: string, displayName: string, email: string, createdAt: string, totalPrice: any, status: PaymentStatus }; @@ -4072,7 +4072,7 @@ export const TransferConsentFormRegistryFragmentDoc = {"kind":"Document","defini export const AdminOrderPaymentStampFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderPaymentStamp"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedPaymentStampType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}}]} as unknown as DocumentNode; export const AdminOrderReceiptFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderReceipt"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedReceiptType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode; export const AdminOrderCodeFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderCode"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedCodeType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"literateCode"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"usedOn"}},{"kind":"Field","name":{"kind":"Name","value":"productText"}}]}}]} as unknown as DocumentNode; -export const NewOrderProductFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NewOrderProduct"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; +export const NewOrderProductFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NewOrderProduct"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; export const OrderListFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"OrderList"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullOrderType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode; export const ProductChoiceFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductChoice"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}}]} as unknown as DocumentNode; export const FullProfileFieldSelectorFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullProfileFieldSelector"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileFieldSelectorType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}}]}}]} as unknown as DocumentNode; @@ -4152,7 +4152,7 @@ export const CancelAndRefundOrderDocument = {"kind":"Document","definitions":[{" export const MarkOrderAsPaidDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"MarkOrderAsPaid"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"MarkOrderAsPaidInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"markOrderAsPaid"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const AdminOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phone"}},{"kind":"Field","name":{"kind":"Name","value":"canRefund"}},{"kind":"Field","name":{"kind":"Name","value":"canRefundManually"}},{"kind":"Field","name":{"kind":"Name","value":"canMarkAsPaid"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"paymentStamps"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderPaymentStamp"}}]}},{"kind":"Field","name":{"kind":"Name","value":"receipts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderReceipt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"codes"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AdminOrderCode"}}]}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderPaymentStamp"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedPaymentStampType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"provider"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"data"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderReceipt"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedReceiptType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"correlationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AdminOrderCode"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedCodeType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"code"}},{"kind":"Field","name":{"kind":"Name","value":"literateCode"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"usedOn"}},{"kind":"Field","name":{"kind":"Name","value":"productText"}}]}}]} as unknown as DocumentNode; export const AdminCreateOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AdminCreateOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateOrderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}},{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; -export const NewOrderPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NewOrderPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NewOrderProduct"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NewOrderProduct"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; +export const NewOrderPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"NewOrderPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NewOrderProduct"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NewOrderProduct"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}},{"kind":"Field","name":{"kind":"Name","value":"isAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"availableFrom"}},{"kind":"Field","name":{"kind":"Name","value":"availableUntil"}},{"kind":"Field","name":{"kind":"Name","value":"countPaid"}},{"kind":"Field","name":{"kind":"Name","value":"countReserved"}},{"kind":"Field","name":{"kind":"Name","value":"countAvailable"}},{"kind":"Field","name":{"kind":"Name","value":"maxPerOrder"}}]}}]} as unknown as DocumentNode; export const AdminOrderListWithOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminOrderListWithOrders"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"filters"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"DimensionFilterInput"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"search"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}},"defaultValue":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProductChoice"}}]}},{"kind":"Field","name":{"kind":"Name","value":"orders"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"Variable","name":{"kind":"Name","value":"filters"}}},{"kind":"Argument","name":{"kind":"Name","value":"search"},"value":{"kind":"Variable","name":{"kind":"Name","value":"search"}}},{"kind":"Argument","name":{"kind":"Name","value":"returnNone"},"value":{"kind":"Variable","name":{"kind":"Name","value":"returnNone"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"OrderList"}}]}},{"kind":"Field","name":{"kind":"Name","value":"countTotalOrders"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProductChoice"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProductType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"OrderList"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullOrderType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]} as unknown as DocumentNode; export const CancelOwnOrderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelOwnOrder"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CancelOwnUnpaidOrderInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelOwnUnpaidOrder"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]} as unknown as DocumentNode; export const PersonPageDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PersonPage"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"personId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"event"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"slug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}},{"kind":"Field","name":{"kind":"Name","value":"involvement"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"publicOnly"},"value":{"kind":"BooleanValue","value":false}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CachedDimensionsBadges"}},{"kind":"FragmentSpread","name":{"kind":"Name","value":"DimensionValueSelect"}},{"kind":"Field","name":{"kind":"Name","value":"isKeyDimension"}},{"kind":"Field","name":{"kind":"Name","value":"isShownInDetail"}}]}},{"kind":"Field","name":{"kind":"Name","value":"annotations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"publicOnly"},"value":{"kind":"BooleanValue","value":false}},{"kind":"Argument","name":{"kind":"Name","value":"perksOnly"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AnnotationsFormAnnotation"}}]}},{"kind":"Field","name":{"kind":"Name","value":"person"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"personId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPersonDetail"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"FullProfileFieldSelector"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileFieldSelectorType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonDetailInvolvement"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"LimitedInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"adminLink"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"cachedDimensions"}},{"kind":"Field","name":{"kind":"Name","value":"cachedAnnotations"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CachedDimensionsBadges"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"DimensionValueSelect"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullDimensionType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isTechnical"}},{"kind":"Field","name":{"kind":"Name","value":"isMultiValue"}},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AnnotationsFormAnnotation"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"AnnotationType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"description"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"isComputed"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"InvolvedPersonDetail"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileWithInvolvementType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"nick"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"phoneNumber"}},{"kind":"Field","name":{"kind":"Name","value":"discordHandle"}},{"kind":"Field","name":{"kind":"Name","value":"fullName"}},{"kind":"Field","name":{"kind":"Name","value":"profileFieldSelector"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"FullProfileFieldSelector"}}]}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"involvements"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"InvolvedPersonDetailInvolvement"}}]}}]}}]} as unknown as DocumentNode; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/new/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/new/page.tsx index c21c3c217..2faec7f5c 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/new/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders-admin/new/page.tsx @@ -26,6 +26,7 @@ graphql(` title description price + vatPercentage isAvailable availableFrom availableUntil @@ -172,7 +173,12 @@ export default async function OrdersPage(props: Props) { onSubmit={adminCreateOrder.bind(null, locale, eventSlug)} > {products.map((product) => ( - +
{producT.clientAttributes.countReserved.title}:{" "} From da2e2876eee8a35212dacfae17a1e5d9677d6b16 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:34:08 +0300 Subject: [PATCH 13/31] chore: translation style --- kompassi-v2-frontend/src/translations/en.tsx | 2 +- kompassi-v2-frontend/src/translations/fi.tsx | 2 +- kompassi-v2-frontend/src/translations/sv.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 69f0409bc..782738953 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -544,7 +544,7 @@ const translations = { }, }, serverAttributes: { - vatIncluded: (rate: string) => `incl. ${rate}% VAT`, + vatIncluded: (rate: string) => `incl. VAT ${rate}%`, isAvailable: { untilFurtherNotice: "Available until further notice", untilTime: (formattedTime: string) => diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 30f3dbe6f..3f9760d80 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -540,7 +540,7 @@ const translations: Translations = { }, }, serverAttributes: { - vatIncluded: (rate: string) => `sis. ${rate}% ALV`, + vatIncluded: (rate: string) => `sis. ALV ${rate}%`, isAvailable: { untilFurtherNotice: "Saatavilla toistaiseksi", untilTime: (formattedTime: string) => diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index b34c8ab44..3d55165c1 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -532,7 +532,7 @@ const translations: Translations = { }, }, serverAttributes: { - vatIncluded: (rate: string) => `inkl. ${rate}% moms`, + vatIncluded: (rate: string) => `inkl. moms${rate}%`, isAvailable: { untilFurtherNotice: "Tillgänglig tills vidare", untilTime: (formattedTime: string) => From f863378a262dd0a7ee57180f55dbb161de35ee99 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:36:40 +0300 Subject: [PATCH 14/31] fix(tickets_v2): typecheck --- kompassi/tickets_v2/optimized_server/providers/paytrail.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kompassi/tickets_v2/optimized_server/providers/paytrail.py b/kompassi/tickets_v2/optimized_server/providers/paytrail.py index 1a8209377..62bd9a726 100644 --- a/kompassi/tickets_v2/optimized_server/providers/paytrail.py +++ b/kompassi/tickets_v2/optimized_server/providers/paytrail.py @@ -94,12 +94,12 @@ class PaytrailItem(pydantic.BaseModel): description: str @classmethod - def from_order_products(cls, order_products: list[OrderProduct]) -> list[PaytrailItem]: + def from_order_products(cls, order_products: list[OrderProduct]) -> list[Self]: return [ cls( unit_price=int(op.price * 100), units=op.quantity, - vat_percentage=op.vat_percentage, + vat_percentage=float(op.vat_percentage), product_code=str(i + 1), description=op.title, ) From 2f48633ce6b33d0eb3fdee0d4bdbcbd417611172 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:47:10 +0300 Subject: [PATCH 15/31] feat: add VAT by month report to tickets_v2 reports Rows are months, columns are VAT percentages found in paid orders plus a total column. Only paid orders (status=3) are included; refunds are noted in the footer. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/reports/__init__.py | 2 + .../reports/sql/report_vat_by_month.sql | 22 +++++ kompassi/tickets_v2/reports/vat_by_month.py | 97 +++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 kompassi/tickets_v2/reports/sql/report_vat_by_month.sql create mode 100644 kompassi/tickets_v2/reports/vat_by_month.py diff --git a/kompassi/tickets_v2/reports/__init__.py b/kompassi/tickets_v2/reports/__init__.py index e36ef9d51..94bd28737 100644 --- a/kompassi/tickets_v2/reports/__init__.py +++ b/kompassi/tickets_v2/reports/__init__.py @@ -9,6 +9,7 @@ from .sales_by_payment_provider import sales_by_payment_provider from .ticket_exchange_by_hour import TicketExchangeByHour from .ticket_exchange_by_product import ticket_exchange_by_product +from .vat_by_month import VatByMonth REPORTS = dict( orders_by_payment_status=OrdersByPaymentStatus.report, @@ -16,6 +17,7 @@ sales_by_payment_provider=sales_by_payment_provider, ticket_exchange_by_product=ticket_exchange_by_product, ticket_exchange_by_hour=TicketExchangeByHour.report, + vat_by_month=VatByMonth.report, ) diff --git a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql new file mode 100644 index 000000000..7af646d99 --- /dev/null +++ b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql @@ -0,0 +1,22 @@ +select + to_char( + date_trunc( + 'month', + to_timestamp( + ('x' || left(replace(o.id::text, '-', ''), 12))::bit(48)::bigint / 1000.0 + ) at time zone %(event_timezone)s + ), + 'YYYY-MM' + ) as year_month, + p.vat_percentage, + sum(p.price * pd.quantity::numeric) as gross_sales +from + tickets_v2_order o + join lateral jsonb_each_text(o.product_data) as pd(product_id, quantity) on true + join tickets_v2_product p on p.id = pd.product_id::int +where + o.event_id = %(event_id)s + and o.cached_status = 3 + and pd.quantity::int > 0 +group by 1, 2 +order by 1, 2 diff --git a/kompassi/tickets_v2/reports/vat_by_month.py b/kompassi/tickets_v2/reports/vat_by_month.py new file mode 100644 index 000000000..c0d48dc4d --- /dev/null +++ b/kompassi/tickets_v2/reports/vat_by_month.py @@ -0,0 +1,97 @@ +from __future__ import annotations + +from decimal import Decimal +from pathlib import Path + +from django.db import connection + +from kompassi.core.models.event import Event +from kompassi.graphql_api.language import DEFAULT_LANGUAGE +from kompassi.reports.models.column import Column +from kompassi.reports.models.enums import TotalBy, TypeOfColumn +from kompassi.reports.models.report import Report + +SQL_DIR = Path(__file__).parent / "sql" + + +def _format_vat_rate(rate: Decimal) -> dict[str, str]: + normalized = rate.normalize() + en = f"{normalized}%" + fi = f"{str(normalized).replace('.', ',')}%" + return dict(fi=fi, en=en) + + +class VatByMonth: + query = (SQL_DIR / "report_vat_by_month.sql").read_text() + + @classmethod + def report(cls, event: Event, lang: str = DEFAULT_LANGUAGE) -> Report: + with connection.cursor() as cursor: + cursor.execute(cls.query, dict(event_id=event.id, event_timezone=event.timezone_name)) + raw_rows = cursor.fetchall() + + if not raw_rows: + return Report( + slug="vat_by_month", + title=dict(fi="ALV-erittely kuukausittain", en="VAT by month"), + columns=[ + Column( + slug="month", + title=dict(fi="Kuukausi", en="Month"), + type=TypeOfColumn.STRING, + total_by=TotalBy.NONE, + ) + ], + rows=[], + lang=lang, + ) + + months: list[str] = sorted({row[0] for row in raw_rows}) + vat_rates: list[Decimal] = sorted({row[1] for row in raw_rows}) + data: dict[tuple[str, Decimal], Decimal] = {(row[0], row[1]): row[2] for row in raw_rows} + + columns: list[Column] = [ + Column( + slug="month", + title=dict(fi="Kuukausi", en="Month"), + type=TypeOfColumn.STRING, + total_by=TotalBy.NONE, + ), + *[ + Column( + slug=f"vat_{rate}", + title=_format_vat_rate(rate), + type=TypeOfColumn.CURRENCY, + ) + for rate in vat_rates + ], + Column( + slug="total", + title=dict(fi="Yhteensä", en="Total"), + type=TypeOfColumn.CURRENCY, + ), + ] + + rows: list[list] = [] + for month in months: + row_total = Decimal(0) + row: list = [month] + for rate in vat_rates: + gross = data.get((month, rate), Decimal(0)) + row.append(float(gross)) + row_total += gross + row.append(float(row_total)) + rows.append(row) + + return Report( + slug="vat_by_month", + title=dict(fi="ALV-erittely kuukausittain", en="VAT by month"), + columns=columns, + rows=rows, + has_total_row=True, + lang=lang, + footer=dict( + fi="Vain maksetut tilaukset on laskettu mukaan. Hyvitykset eivät sisälly raporttiin.", + en="Only paid orders are included. Refunds are not reflected in this report.", + ), + ) From 136f2b4a47664e56801648c7164dc035a4d589d1 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:52:42 +0300 Subject: [PATCH 16/31] fix: report VAT tax amount instead of gross revenue VAT amount = gross * rate / (100 + rate) since prices are VAT-inclusive. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/reports/sql/report_vat_by_month.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql index 7af646d99..3d16e950c 100644 --- a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql +++ b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql @@ -9,7 +9,7 @@ select 'YYYY-MM' ) as year_month, p.vat_percentage, - sum(p.price * pd.quantity::numeric) as gross_sales + sum(p.price * pd.quantity::numeric * p.vat_percentage / (100 + p.vat_percentage)) as vat_amount from tickets_v2_order o join lateral jsonb_each_text(o.product_data) as pd(product_id, quantity) on true From 29711eb27421caf9bfdc3e50e81b4e65b08570db Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Tue, 12 May 2026 23:53:29 +0300 Subject: [PATCH 17/31] fix: omit 0% VAT rate from VAT by month report Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/reports/sql/report_vat_by_month.sql | 1 + 1 file changed, 1 insertion(+) diff --git a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql index 3d16e950c..2e2c8d3bf 100644 --- a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql +++ b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql @@ -18,5 +18,6 @@ where o.event_id = %(event_id)s and o.cached_status = 3 and pd.quantity::int > 0 + and p.vat_percentage > 0 group by 1, 2 order by 1, 2 From 0cb79ccbf29186637e9ddb758db0bd5795fd2225 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Wed, 13 May 2026 00:02:10 +0300 Subject: [PATCH 18/31] refactor(tickets_v2): tidy VAT by month report - Pull title, column title, and footer dicts into module-level constants so the empty-result and non-empty paths share the same wording. - Use the shared format_vat_rate helper for column titles (with Swedish added) instead of duplicating the formatting logic. - Quantize values to cents in Decimal space before converting to float so rounding is deterministic and the SUM total row matches the per-cell sums. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/reports/vat_by_month.py | 68 ++++++++++----------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/kompassi/tickets_v2/reports/vat_by_month.py b/kompassi/tickets_v2/reports/vat_by_month.py index c0d48dc4d..3ca4539a6 100644 --- a/kompassi/tickets_v2/reports/vat_by_month.py +++ b/kompassi/tickets_v2/reports/vat_by_month.py @@ -11,14 +11,27 @@ from kompassi.reports.models.enums import TotalBy, TypeOfColumn from kompassi.reports.models.report import Report +from ..optimized_server.utils.formatting import format_vat_rate + SQL_DIR = Path(__file__).parent / "sql" +TITLE = dict( + fi="ALV-erittely kuukausittain", + en="VAT by month", + sv="Moms per månad", +) +MONTH_COLUMN_TITLE = dict(fi="Kuukausi", en="Month", sv="Månad") +TOTAL_COLUMN_TITLE = dict(fi="Yhteensä", en="Total", sv="Totalt") +FOOTER = dict( + fi="Vain maksetut tilaukset on laskettu mukaan. Hyvitykset eivät sisälly raporttiin.", + en="Only paid orders are included. Refunds are not reflected in this report.", + sv="Endast betalda beställningar ingår. Återbetalningar visas inte i rapporten.", +) +CENT = Decimal("0.01") + -def _format_vat_rate(rate: Decimal) -> dict[str, str]: - normalized = rate.normalize() - en = f"{normalized}%" - fi = f"{str(normalized).replace('.', ',')}%" - return dict(fi=fi, en=en) +def _vat_column_title(rate: Decimal) -> dict[str, str]: + return {lang: f"{format_vat_rate(rate, lang)}%" for lang in ("fi", "en", "sv")} class VatByMonth: @@ -30,68 +43,49 @@ def report(cls, event: Event, lang: str = DEFAULT_LANGUAGE) -> Report: cursor.execute(cls.query, dict(event_id=event.id, event_timezone=event.timezone_name)) raw_rows = cursor.fetchall() - if not raw_rows: - return Report( - slug="vat_by_month", - title=dict(fi="ALV-erittely kuukausittain", en="VAT by month"), - columns=[ - Column( - slug="month", - title=dict(fi="Kuukausi", en="Month"), - type=TypeOfColumn.STRING, - total_by=TotalBy.NONE, - ) - ], - rows=[], - lang=lang, - ) - - months: list[str] = sorted({row[0] for row in raw_rows}) vat_rates: list[Decimal] = sorted({row[1] for row in raw_rows}) + months: list[str] = sorted({row[0] for row in raw_rows}) data: dict[tuple[str, Decimal], Decimal] = {(row[0], row[1]): row[2] for row in raw_rows} columns: list[Column] = [ Column( slug="month", - title=dict(fi="Kuukausi", en="Month"), + title=MONTH_COLUMN_TITLE, type=TypeOfColumn.STRING, total_by=TotalBy.NONE, ), - *[ + *( Column( slug=f"vat_{rate}", - title=_format_vat_rate(rate), + title=_vat_column_title(rate), type=TypeOfColumn.CURRENCY, ) for rate in vat_rates - ], + ), Column( slug="total", - title=dict(fi="Yhteensä", en="Total"), + title=TOTAL_COLUMN_TITLE, type=TypeOfColumn.CURRENCY, ), ] rows: list[list] = [] for month in months: - row_total = Decimal(0) row: list = [month] + row_total = Decimal(0) for rate in vat_rates: - gross = data.get((month, rate), Decimal(0)) - row.append(float(gross)) - row_total += gross + vat = data.get((month, rate), Decimal(0)).quantize(CENT) + row.append(float(vat)) + row_total += vat row.append(float(row_total)) rows.append(row) return Report( slug="vat_by_month", - title=dict(fi="ALV-erittely kuukausittain", en="VAT by month"), + title=TITLE, columns=columns, rows=rows, - has_total_row=True, + has_total_row=bool(rows), lang=lang, - footer=dict( - fi="Vain maksetut tilaukset on laskettu mukaan. Hyvitykset eivät sisälly raporttiin.", - en="Only paid orders are included. Refunds are not reflected in this report.", - ), + footer=FOOTER, ) From 2a4c437fca4696f913241140024f6c90d62c7773 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Wed, 13 May 2026 00:03:04 +0300 Subject: [PATCH 19/31] refactor(tickets_v2): centralize VAT breakdown calculation Move the per-rate gross/vat/net summation into VatBreakdownLine.from_order_products so the formula lives next to the model and OrderMixin.vat_breakdown is a one-liner. Also hoists the local defaultdict import to module scope. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/models/order.py | 13 +----------- .../optimized_server/models/order.py | 20 ++++++++++++++++++- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/kompassi/tickets_v2/models/order.py b/kompassi/tickets_v2/models/order.py index c5859ffaa..fe5b9af61 100644 --- a/kompassi/tickets_v2/models/order.py +++ b/kompassi/tickets_v2/models/order.py @@ -92,18 +92,7 @@ def products(self) -> list[OrderProduct]: @cached_property def vat_breakdown(self) -> list[VatBreakdownLine]: - from collections import defaultdict - - totals: dict[Decimal, Decimal] = defaultdict(Decimal) - for op in self.products: - totals[op.vat_percentage] += op.price * op.quantity - result = [] - for rate in sorted(totals): - gross = totals[rate] - vat = (gross * rate / (100 + rate)).quantize(Decimal("0.01")) - net = gross - vat - result.append(VatBreakdownLine(rate=rate, gross=gross, vat=vat, net=net)) - return result + return VatBreakdownLine.from_order_products(self.products) @cached_property def etickets(self) -> list[Product]: diff --git a/kompassi/tickets_v2/optimized_server/models/order.py b/kompassi/tickets_v2/optimized_server/models/order.py index 120985ecb..06c518668 100644 --- a/kompassi/tickets_v2/optimized_server/models/order.py +++ b/kompassi/tickets_v2/optimized_server/models/order.py @@ -1,10 +1,11 @@ from __future__ import annotations import json +from collections import defaultdict from datetime import datetime from decimal import Decimal from pathlib import Path -from typing import Annotated, Any, ClassVar +from typing import Annotated, Any, ClassVar, Self from uuid import UUID import pydantic @@ -128,12 +129,29 @@ class OrderProduct(pydantic.BaseModel): vat_percentage: Decimal = pydantic.Field(serialization_alias="vatPercentage") +CENT = Decimal("0.01") + + class VatBreakdownLine(pydantic.BaseModel): rate: Decimal gross: Decimal vat: Decimal net: Decimal + @classmethod + def from_order_products(cls, order_products: list[OrderProduct]) -> list[Self]: + totals: dict[Decimal, Decimal] = defaultdict(Decimal) + for op in order_products: + totals[op.vat_percentage] += op.price * op.quantity + + breakdown: list[Self] = [] + for rate in sorted(totals): + gross = totals[rate] + vat = (gross * rate / (100 + rate)).quantize(CENT) + net = gross - vat + breakdown.append(cls(rate=rate, gross=gross, vat=vat, net=net)) + return breakdown + class Order(pydantic.BaseModel, populate_by_name=True): id: UUID From 795efd0a5ef32f12679bf764d0e09c9ad73a641d Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Wed, 13 May 2026 00:04:38 +0300 Subject: [PATCH 20/31] fix(tickets_v2): avoid scientific notation in format_vat_rate Decimal('10.00').normalize() returns Decimal('1E+1'), so the previous str(rate.normalize()) produced '1E+1' for 10% VAT and '1E+2' for 100%, breaking receipt emails (used as a Django template filter) and the admin order detail VAT rows. Use {rate:f} formatting and strip trailing zeros from the string instead. The asserted doctest output now actually holds. Co-Authored-By: Claude Sonnet 4.6 --- .../tickets_v2/optimized_server/utils/formatting.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/kompassi/tickets_v2/optimized_server/utils/formatting.py b/kompassi/tickets_v2/optimized_server/utils/formatting.py index 0cbb5a0ae..41bc16f44 100644 --- a/kompassi/tickets_v2/optimized_server/utils/formatting.py +++ b/kompassi/tickets_v2/optimized_server/utils/formatting.py @@ -22,6 +22,9 @@ def format_vat_rate(rate: Decimal, language: str = "en") -> str: Format a VAT rate for display, stripping unnecessary trailing zeros. Uses comma as decimal separator for Finnish and Swedish locales. + Decimal.normalize() is unsuitable here because it produces scientific + notation for values like Decimal('10.00') -> Decimal('1E+1'). + >>> format_vat_rate(Decimal('25.50')) '25.5' >>> format_vat_rate(Decimal('25.50'), 'fi') @@ -32,10 +35,16 @@ def format_vat_rate(rate: Decimal, language: str = "en") -> str: '10' >>> format_vat_rate(Decimal('0')) '0' + >>> format_vat_rate(Decimal('0.00')) + '0' >>> format_vat_rate(Decimal('13.50'), 'sv') '13,5' + >>> format_vat_rate(Decimal('0.50'), 'fi') + '0,5' """ - result = str(rate.normalize()) + result = f"{rate:f}" + if "." in result: + result = result.rstrip("0").rstrip(".") if language in ("fi", "sv"): result = result.replace(".", ",") return result From 169b4e2ca4b1dcba15fedabae4eaf62edaeebf1b Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Wed, 13 May 2026 00:05:48 +0300 Subject: [PATCH 21/31] perf(tickets_v2): skip Order.get for zero-price orders in create_order Both NullProvider and PaytrailProvider short-circuit zero-price orders before reading order_products, so the extra Order.get round trip after order.save() is wasted work for those orders. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/optimized_server/app.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/kompassi/tickets_v2/optimized_server/app.py b/kompassi/tickets_v2/optimized_server/app.py index be4968bbc..1a4432a1d 100644 --- a/kompassi/tickets_v2/optimized_server/app.py +++ b/kompassi/tickets_v2/optimized_server/app.py @@ -13,7 +13,7 @@ from .excs import InvalidProducts, NotEnoughTickets, ProviderCannot, UnsaneSituation from .models.enums import PaymentStampType from .models.event import Event -from .models.order import CreateOrderRequest, Order, OrderWithCustomer +from .models.order import CreateOrderRequest, Order, OrderProduct, OrderWithCustomer from .models.product import Product from .providers.paytrail import PaymentCallback @@ -104,10 +104,15 @@ async def create_order( try: async with db.transaction(): result = await order.save(db, event.id) - fetched_order = await Order.get(db, event.id, result.order_id) - if fetched_order is None: - raise UnsaneSituation("Order not found after creation") - request, request_stamp = provider.prepare_for_new_order(order, result, fetched_order.products) + # Providers short-circuit zero-price orders without using products, + # so skip the extra Order.get round trip in that case. + order_products: list[OrderProduct] = [] + if result.total_price > 0: + fetched_order = await Order.get(db, event.id, result.order_id) + if fetched_order is None: + raise UnsaneSituation("Order not found after creation") + order_products = fetched_order.products + request, request_stamp = provider.prepare_for_new_order(order, result, order_products) await request_stamp.save(db) except NotEnoughTickets as e: raise HTTPException(409, "NOT_ENOUGH_TICKETS") from e From 2f3cf5bc6ec8ac64817a194f7987e75328117482 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Wed, 13 May 2026 00:16:17 +0300 Subject: [PATCH 22/31] test(tickets_v2): add VAT branch unit and integration tests Unit: - format_vat_rate parametrized over the edge cases that broke before the scientific-notation fix (10.00 -> '10', not '1E+1') - VatBreakdownLine.from_order_products across empty, multi-rate, and zero-rate inputs Integration (pytest-django): - VatByMonth.report on an empty event - A full run with multiple months, multiple VAT rates, an unpaid order (excluded by status filter) and a zero-VAT paid order (excluded by the vat_percentage > 0 filter) - UTC-vs-Europe/Helsinki month boundary check - Localized VAT column titles Also fix Report.total_row showing '' instead of 'Total' in the first column: the month column was using total_by=TotalBy.NONE which suppresses the label; default total_by=SUM is the right choice for a STRING header column. Co-Authored-By: Claude Sonnet 4.6 --- kompassi/tickets_v2/reports/vat_by_month.py | 5 +- kompassi/tickets_v2/tests.py | 256 +++++++++++++++++++- 2 files changed, 258 insertions(+), 3 deletions(-) diff --git a/kompassi/tickets_v2/reports/vat_by_month.py b/kompassi/tickets_v2/reports/vat_by_month.py index 3ca4539a6..a6f493858 100644 --- a/kompassi/tickets_v2/reports/vat_by_month.py +++ b/kompassi/tickets_v2/reports/vat_by_month.py @@ -8,7 +8,7 @@ from kompassi.core.models.event import Event from kompassi.graphql_api.language import DEFAULT_LANGUAGE from kompassi.reports.models.column import Column -from kompassi.reports.models.enums import TotalBy, TypeOfColumn +from kompassi.reports.models.enums import TypeOfColumn from kompassi.reports.models.report import Report from ..optimized_server.utils.formatting import format_vat_rate @@ -52,7 +52,8 @@ def report(cls, event: Event, lang: str = DEFAULT_LANGUAGE) -> Report: slug="month", title=MONTH_COLUMN_TITLE, type=TypeOfColumn.STRING, - total_by=TotalBy.NONE, + # NOTE: total_by defaults to SUM, which is what makes the total + # row label show "Total" in column 0 (see Report.get_total_row). ), *( Column( diff --git a/kompassi/tickets_v2/tests.py b/kompassi/tickets_v2/tests.py index b1d59c85e..9c7f137ef 100644 --- a/kompassi/tickets_v2/tests.py +++ b/kompassi/tickets_v2/tests.py @@ -1,4 +1,6 @@ import json +from datetime import UTC, datetime +from decimal import Decimal from functools import cached_property from typing import Any, Literal from uuid import UUID, uuid4 @@ -8,13 +10,17 @@ import requests from kompassi.core.models.event import Event +from kompassi.tickets_v2.models.order import Order +from kompassi.tickets_v2.models.product import Product from kompassi.tickets_v2.optimized_server.models.api import CreateOrderResponse, GetOrderResponse, GetProductsResponse from kompassi.tickets_v2.optimized_server.models.customer import Customer from kompassi.tickets_v2.optimized_server.models.enums import PaymentStatus -from kompassi.tickets_v2.optimized_server.models.order import CreateOrderRequest +from kompassi.tickets_v2.optimized_server.models.order import CreateOrderRequest, OrderProduct, VatBreakdownLine from kompassi.tickets_v2.optimized_server.providers.paytrail import PaymentCallback, PaytrailStatus +from kompassi.tickets_v2.optimized_server.utils.formatting import format_vat_rate from kompassi.tickets_v2.optimized_server.utils.paytrail_hmac import calculate_hmac from kompassi.tickets_v2.optimized_server.utils.uuid7 import uuid7 +from kompassi.tickets_v2.reports.vat_by_month import VatByMonth PAYTRAIL_TEST_ACCOUNT = "375917" PAYTRAIL_TEST_SECRET = "SAIPPUAKAUPPIAS" @@ -234,3 +240,251 @@ def test_make_order(tickets_v2_client: TicketsV2Client): # user redirected to order page again get_order_response = tickets_v2_client.get_order(order_response.order_id) assert get_order_response.order.status == PaymentStatus.PAID + + +# --------------------------------------------------------------------------- +# VAT formatting / breakdown unit tests +# --------------------------------------------------------------------------- + + +@pytest.mark.parametrize( + "rate,expected_en,expected_fi", + [ + (Decimal("0"), "0", "0"), + (Decimal("0.00"), "0", "0"), + (Decimal("10.00"), "10", "10"), + (Decimal("13.50"), "13.5", "13,5"), + (Decimal("14.00"), "14", "14"), + (Decimal("25.50"), "25.5", "25,5"), + (Decimal("0.50"), "0.5", "0,5"), + (Decimal("99.99"), "99.99", "99,99"), + ], +) +def test_format_vat_rate(rate, expected_en, expected_fi): + """ + Regression test: Decimal('10.00').normalize() returns Decimal('1E+1'), + so a naive str(rate.normalize()) implementation would render '1E+1' + instead of '10' in receipts. + """ + assert format_vat_rate(rate, "en") == expected_en + assert format_vat_rate(rate, "fi") == expected_fi + # Swedish uses the same decimal separator as Finnish + assert format_vat_rate(rate, "sv") == expected_fi + + +def test_vat_breakdown_empty(): + assert VatBreakdownLine.from_order_products([]) == [] + + +def test_vat_breakdown_sums_per_rate_and_returns_sorted(): + products = [ + OrderProduct(title="A", price=Decimal("125.50"), quantity=2, vat_percentage=Decimal("25.50")), + OrderProduct(title="B", price=Decimal("114.00"), quantity=1, vat_percentage=Decimal("14.00")), + OrderProduct(title="C", price=Decimal("125.50"), quantity=1, vat_percentage=Decimal("25.50")), + ] + breakdown = VatBreakdownLine.from_order_products(products) + + # Two rates present, sorted ascending. + assert [line.rate for line in breakdown] == [Decimal("14.00"), Decimal("25.50")] + + # 14% line: 1 * 114 = 114 gross, VAT = 114 * 14/114 = 14 + assert breakdown[0].gross == Decimal("114.00") + assert breakdown[0].vat == Decimal("14.00") + assert breakdown[0].net == Decimal("100.00") + + # 25.5% line: 3 * 125.50 = 376.50 gross, VAT = 376.50 * 25.5/125.5 = 76.50 + assert breakdown[1].gross == Decimal("376.50") + assert breakdown[1].vat == Decimal("76.50") + assert breakdown[1].net == Decimal("300.00") + + +def test_vat_breakdown_zero_rate_kept(): + """ + The breakdown itself preserves 0% rates (used in receipts to itemize + zero-rated lines). Filtering of 0% is the VAT-by-month report's concern. + """ + products = [ + OrderProduct(title="Free", price=Decimal("5.00"), quantity=1, vat_percentage=Decimal("0")), + ] + breakdown = VatBreakdownLine.from_order_products(products) + assert len(breakdown) == 1 + assert breakdown[0].rate == Decimal("0") + assert breakdown[0].gross == Decimal("5.00") + assert breakdown[0].vat == Decimal("0.00") + assert breakdown[0].net == Decimal("5.00") + + +# --------------------------------------------------------------------------- +# VAT-by-month report integration tests +# --------------------------------------------------------------------------- + + +def _make_order( + event: Event, + when: datetime, + product_data: dict[int, int], + status: PaymentStatus = PaymentStatus.PAID, +) -> UUID: + """ + Insert a tickets_v2_order row directly via SQL. + + Bypasses the ORM because tickets_v2_order.order_number is GENERATED ALWAYS + AS IDENTITY at the DB layer, so Django can't INSERT through the column; + the production code path goes through create_order.sql for the same reason. + Returns the order id. + """ + from django.db import connection + + order_id = uuid7(when) + with connection.cursor() as cursor: + cursor.execute( + """ + insert into tickets_v2_order + (id, event_id, cached_status, cached_price, language, product_data, + first_name, last_name, email, phone) + values + (%s, %s, %s, %s, %s, %s::jsonb, %s, %s, %s, %s) + """, + [ + str(order_id), + event.id, + status.value, + "0", + "en", + json.dumps({str(pid): qty for pid, qty in product_data.items()}), + "Test", + "Customer", + "test@example.com", + "", + ], + ) + return order_id + + +@pytest.fixture +def vat_report_event(db): + event, _ = Event.get_or_create_dummy(name="VAT report test event") + # Sanity-check the timezone the report relies on for month bucketing. + assert event.timezone_name == "Europe/Helsinki" + Order.ensure_partition(event) + return event + + +@pytest.mark.django_db +def test_vat_by_month_report_empty(vat_report_event: Event): + """No orders → no rows, but the report still renders with a month column.""" + report = VatByMonth.report(vat_report_event, "en") + assert report.slug == "vat_by_month" + assert report.rows == [] + assert [c.slug for c in report.columns] == ["month", "total"] + assert report.total_row is None # has_total_row is False when there are no rows + + +@pytest.mark.django_db +def test_vat_by_month_report_basic(vat_report_event: Event): + """ + Multiple VAT rates across multiple months, with an unpaid order and a + zero-VAT order included to verify both filters. + """ + # Prices chosen so VAT comes out to clean Decimals: + # - 125.50 @ 25.5% → VAT/unit = 125.50 * 25.5 / 125.5 = 25.50 + # - 114.00 @ 14% → VAT/unit = 114.00 * 14 / 114 = 14.00 + standard = Product.objects.create( + event=vat_report_event, + title="Standard product", + description="", + price=Decimal("125.50"), + vat_percentage=Decimal("25.50"), + ) + reduced = Product.objects.create( + event=vat_report_event, + title="Food product", + description="", + price=Decimal("114.00"), + vat_percentage=Decimal("14.00"), + ) + zero_rated = Product.objects.create( + event=vat_report_event, + title="Free product", + description="", + price=Decimal("5.00"), + vat_percentage=Decimal("0"), + ) + + # Jan 2026 (Helsinki): 1× standard → 25.5% column = 25.50 + _make_order(vat_report_event, datetime(2026, 1, 15, 12, 0, tzinfo=UTC), {standard.id: 1}) + # Feb 2026 (Helsinki): 1× standard + 2× reduced → 25.5% = 25.50, 14% = 28.00 + _make_order(vat_report_event, datetime(2026, 2, 10, 12, 0, tzinfo=UTC), {standard.id: 1, reduced.id: 2}) + # Unpaid Feb order (must be excluded) + _make_order( + vat_report_event, + datetime(2026, 2, 20, 12, 0, tzinfo=UTC), + {standard.id: 1}, + status=PaymentStatus.PENDING, + ) + # Paid zero-VAT Feb order (must be excluded) + _make_order(vat_report_event, datetime(2026, 2, 25, 12, 0, tzinfo=UTC), {zero_rated.id: 1}) + + report = VatByMonth.report(vat_report_event, "en") + + column_slugs = [c.slug for c in report.columns] + assert column_slugs == ["month", "vat_14.00", "vat_25.50", "total"] + + assert len(report.rows) == 2 + jan, feb = report.rows + assert jan == ["2026-01", 0.00, 25.50, 25.50] + assert feb == ["2026-02", 28.00, 25.50, 53.50] + + # Total row sums each column (skipping the month column, which is total_by=NONE). + assert report.total_row is not None + month_label, total_14, total_25_5, grand_total = report.total_row + assert month_label == "Total" + assert total_14 == pytest.approx(28.00) + assert total_25_5 == pytest.approx(51.00) + assert grand_total == pytest.approx(79.00) + + +@pytest.mark.django_db +def test_vat_by_month_report_timezone_boundary(vat_report_event: Event): + """ + An order at 23:30 UTC on Jan 31 falls on Feb 1 in Helsinki (UTC+2), + so the report should bucket it in February. + """ + product = Product.objects.create( + event=vat_report_event, + title="Standard", + description="", + price=Decimal("125.50"), + vat_percentage=Decimal("25.50"), + ) + # UTC moment that is already in February when projected into Europe/Helsinki. + _make_order(vat_report_event, datetime(2026, 1, 31, 23, 30, tzinfo=UTC), {product.id: 1}) + + report = VatByMonth.report(vat_report_event, "en") + assert [row[0] for row in report.rows] == ["2026-02"] + + +@pytest.mark.django_db +def test_vat_by_month_report_localized_titles(vat_report_event: Event): + """Column titles for VAT rates follow the requested locale's separator.""" + Product.objects.create( + event=vat_report_event, + title="Standard", + description="", + price=Decimal("125.50"), + vat_percentage=Decimal("25.50"), + ) + _make_order( + vat_report_event, + datetime(2026, 3, 15, 12, 0, tzinfo=UTC), + {vat_report_event.products.get().id: 1}, + ) + + en_report = VatByMonth.report(vat_report_event, "en") + fi_report = VatByMonth.report(vat_report_event, "fi") + # The Column.title is a dict that resolve_localized_field picks from at GraphQL + # serialization time; we just verify both locales are populated correctly. + vat_col_en = next(c for c in en_report.columns if c.slug == "vat_25.50") + vat_col_fi = next(c for c in fi_report.columns if c.slug == "vat_25.50") + assert vat_col_en.title["en"] == "25.5%" + assert vat_col_fi.title["fi"] == "25,5%" From a29a9b7751afdaf77e7ce7c2bbef178540d5e227 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 12:50:21 +0300 Subject: [PATCH 23/31] feat(tickets_v2): add seller info to order receipts and order pages Add Organization.business_id (Y-tunnus), expose it via GraphQL and the optimized REST API, and display seller name, contact email, and business ID on order confirmation emails and both customer-facing order pages. Remove the outdated non-profit VAT exemption footnote from email footers. Co-Authored-By: Claude Sonnet 4.6 --- kompassi-v2-frontend/src/__generated__/gql.ts | 6 ++-- .../src/__generated__/graphql.ts | 10 ++++-- .../[eventSlug]/orders/[orderId]/page.tsx | 5 ++- .../orders/[eventSlug]/[orderId]/page.tsx | 15 ++++++++ .../src/components/tickets/SellerSection.tsx | 34 +++++++++++++++++++ kompassi-v2-frontend/src/services/tickets.ts | 5 +++ kompassi-v2-frontend/src/translations/en.tsx | 5 +++ kompassi-v2-frontend/src/translations/fi.tsx | 5 +++ kompassi-v2-frontend/src/translations/sv.tsx | 5 +++ kompassi/core/graphql/event_limited.py | 8 +++++ kompassi/core/graphql/organization_limited.py | 1 + .../0044_organization_business_id.py | 21 ++++++++++++ kompassi/core/models/organization.py | 8 +++++ kompassi/tickets_v2/graphql/order_profile.py | 13 +++++++ kompassi/tickets_v2/models/receipt.py | 11 +++++- kompassi/tickets_v2/optimized_server/app.py | 5 +++ .../optimized_server/models/event.py | 4 +++ .../models/sql/get_events.sql | 5 ++- .../templates/tickets_v2_footer_en.eml | 5 +-- .../templates/tickets_v2_footer_fi.eml | 4 ++- .../templates/tickets_v2_receipt_en.eml | 1 + .../templates/tickets_v2_receipt_fi.eml | 1 + 22 files changed, 166 insertions(+), 11 deletions(-) create mode 100644 kompassi-v2-frontend/src/components/tickets/SellerSection.tsx create mode 100644 kompassi/core/migrations/0044_organization_business_id.py diff --git a/kompassi-v2-frontend/src/__generated__/gql.ts b/kompassi-v2-frontend/src/__generated__/gql.ts index 6d190478f..061d8cda2 100644 --- a/kompassi-v2-frontend/src/__generated__/gql.ts +++ b/kompassi-v2-frontend/src/__generated__/gql.ts @@ -180,7 +180,7 @@ type Documents = { "\n mutation RevokeKeyPair($id: String!) {\n revokeKeyPair(id: $id) {\n id\n }\n }\n": typeof types.RevokeKeyPairDocument, "\n fragment ProfileEncryptionKeys on KeyPairType {\n id\n createdAt\n }\n": typeof types.ProfileEncryptionKeysFragmentDoc, "\n query ProfileEncryptionKeys {\n profile {\n keypairs {\n ...ProfileEncryptionKeys\n }\n }\n }\n": typeof types.ProfileEncryptionKeysDocument, - "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": typeof types.ProfileOrderDetailDocument, + "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n ticketsContactEmail\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n organization {\n name\n businessId\n }\n }\n }\n }\n }\n }\n": typeof types.ProfileOrderDetailDocument, "\n mutation ConfirmEmail($input: ConfirmEmailInput!) {\n confirmEmail(input: $input) {\n user {\n email\n }\n }\n }\n": typeof types.ConfirmEmailDocument, "\n fragment ProfileOrder on ProfileOrderType {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n\n event {\n slug\n name\n }\n }\n": typeof types.ProfileOrderFragmentDoc, "\n query ProfileOrders {\n profile {\n tickets {\n orders {\n ...ProfileOrder\n }\n\n haveUnlinkedOrders\n }\n }\n }\n": typeof types.ProfileOrdersDocument, @@ -379,7 +379,7 @@ const documents: Documents = { "\n mutation RevokeKeyPair($id: String!) {\n revokeKeyPair(id: $id) {\n id\n }\n }\n": types.RevokeKeyPairDocument, "\n fragment ProfileEncryptionKeys on KeyPairType {\n id\n createdAt\n }\n": types.ProfileEncryptionKeysFragmentDoc, "\n query ProfileEncryptionKeys {\n profile {\n keypairs {\n ...ProfileEncryptionKeys\n }\n }\n }\n": types.ProfileEncryptionKeysDocument, - "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n": types.ProfileOrderDetailDocument, + "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n ticketsContactEmail\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n organization {\n name\n businessId\n }\n }\n }\n }\n }\n }\n": types.ProfileOrderDetailDocument, "\n mutation ConfirmEmail($input: ConfirmEmailInput!) {\n confirmEmail(input: $input) {\n user {\n email\n }\n }\n }\n": types.ConfirmEmailDocument, "\n fragment ProfileOrder on ProfileOrderType {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n\n event {\n slug\n name\n }\n }\n": types.ProfileOrderFragmentDoc, "\n query ProfileOrders {\n profile {\n tickets {\n orders {\n ...ProfileOrder\n }\n\n haveUnlinkedOrders\n }\n }\n }\n": types.ProfileOrdersDocument, @@ -1093,7 +1093,7 @@ export function graphql(source: "\n query ProfileEncryptionKeys {\n profile /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ -export function graphql(source: "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n }\n }\n }\n }\n }\n"]; +export function graphql(source: "\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n ticketsContactEmail\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n organization {\n name\n businessId\n }\n }\n }\n }\n }\n }\n"): (typeof documents)["\n query ProfileOrderDetail($eventSlug: String!, $orderId: String!) {\n profile {\n tickets {\n order(eventSlug: $eventSlug, id: $orderId) {\n id\n formattedOrderNumber\n createdAt\n totalPrice\n status\n eticketsLink\n canPay\n canCancel\n ticketsContactEmail\n products {\n title\n quantity\n price\n vatPercentage\n }\n\n event {\n slug\n name\n organization {\n name\n businessId\n }\n }\n }\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/kompassi-v2-frontend/src/__generated__/graphql.ts b/kompassi-v2-frontend/src/__generated__/graphql.ts index fb59265c5..0376f7ceb 100644 --- a/kompassi-v2-frontend/src/__generated__/graphql.ts +++ b/kompassi-v2-frontend/src/__generated__/graphql.ts @@ -586,6 +586,7 @@ export type FullEventType = { forms?: Maybe; involvement?: Maybe; name: Scalars['String']['output']; + organization: LimitedOrganizationType; program?: Maybe; /** Tekninen nimi eli "slug" näkyy URL-osoitteissa. Sallittuja merkkejä ovat pienet kirjaimet, numerot ja väliviiva. Teknistä nimeä ei voi muuttaa luomisen jälkeen. */ slug: Scalars['String']['output']; @@ -1124,6 +1125,7 @@ export type LimitedEventType = { __typename?: 'LimitedEventType'; endTime?: Maybe; name: Scalars['String']['output']; + organization: LimitedOrganizationType; /** Tekninen nimi eli "slug" näkyy URL-osoitteissa. Sallittuja merkkejä ovat pienet kirjaimet, numerot ja väliviiva. Teknistä nimeä ei voi muuttaa luomisen jälkeen. */ slug: Scalars['String']['output']; startTime?: Maybe; @@ -1180,6 +1182,8 @@ export type LimitedOrderType = { export type LimitedOrganizationType = { __typename?: 'LimitedOrganizationType'; + /** Finnish business ID (Y-tunnus), eg. 1234567-8. */ + businessId: Scalars['String']['output']; name: Scalars['String']['output']; /** Tekninen nimi eli "slug" näkyy URL-osoitteissa. Sallittuja merkkejä ovat pienet kirjaimet, numerot ja väliviiva. Teknistä nimeä ei voi muuttaa luomisen jälkeen. */ slug: Scalars['String']['output']; @@ -2055,6 +2059,8 @@ export type ProfileOrderType = { /** Returns a link at which the user can view their electronic tickets. They need to be the owner of the order (or an admin) to access that link. Returns null if the order does not contain electronic tickets. */ products: Array; status: PaymentStatus; + /** Contact email for the ticket seller (from the event's tickets meta). */ + ticketsContactEmail: Scalars['String']['output']; totalPrice: Scalars['Decimal']['output']; }; @@ -3963,7 +3969,7 @@ export type ProfileOrderDetailQueryVariables = Exact<{ }>; -export type ProfileOrderDetailQuery = { __typename?: 'Query', profile?: { __typename?: 'OwnProfileType', tickets: { __typename?: 'TicketsV2ProfileMetaType', order?: { __typename?: 'ProfileOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, canPay: boolean, canCancel: boolean, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any, vatPercentage: any }>, event: { __typename?: 'LimitedEventType', slug: string, name: string } } | null } } | null }; +export type ProfileOrderDetailQuery = { __typename?: 'Query', profile?: { __typename?: 'OwnProfileType', tickets: { __typename?: 'TicketsV2ProfileMetaType', order?: { __typename?: 'ProfileOrderType', id: string, formattedOrderNumber: string, createdAt: string, totalPrice: any, status: PaymentStatus, eticketsLink?: string | null, canPay: boolean, canCancel: boolean, ticketsContactEmail: string, products: Array<{ __typename?: 'OrderProductType', title: string, quantity: number, price: any, vatPercentage: any }>, event: { __typename?: 'LimitedEventType', slug: string, name: string, organization: { __typename?: 'LimitedOrganizationType', name: string, businessId: string } } } | null } } | null }; export type ConfirmEmailMutationVariables = Exact<{ input: ConfirmEmailInput; @@ -4256,7 +4262,7 @@ export const TicketsAdminReportsPageDocument = {"kind":"Document","definitions": export const GenerateKeyPairDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"GenerateKeyPair"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"password"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"generateKeyPair"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"password"},"value":{"kind":"Variable","name":{"kind":"Name","value":"password"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const RevokeKeyPairDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RevokeKeyPair"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"revokeKeyPair"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]} as unknown as DocumentNode; export const ProfileEncryptionKeysDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileEncryptionKeys"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"keypairs"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileEncryptionKeys"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileEncryptionKeys"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"KeyPairType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode; -export const ProfileOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"eventSlug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const ProfileOrderDetailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrderDetail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"order"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"eventSlug"},"value":{"kind":"Variable","name":{"kind":"Name","value":"eventSlug"}}},{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"orderId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"ticketsContactEmail"}},{"kind":"Field","name":{"kind":"Name","value":"products"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"vatPercentage"}}]}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"organization"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"businessId"}}]}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const ConfirmEmailDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"ConfirmEmail"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ConfirmEmailInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"confirmEmail"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"email"}}]}}]}}]}}]} as unknown as DocumentNode; export const ProfileOrdersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileOrders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"tickets"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"orders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileOrder"}}]}},{"kind":"Field","name":{"kind":"Name","value":"haveUnlinkedOrders"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileOrder"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileOrderType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"formattedOrderNumber"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"totalPrice"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"eticketsLink"}},{"kind":"Field","name":{"kind":"Name","value":"canPay"}},{"kind":"Field","name":{"kind":"Name","value":"canCancel"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; export const ProfileProgramItemListDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ProfileProgramItemList"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"program"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"programs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userRelation"},"value":{"kind":"EnumValue","value":"HOSTING"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileProgramItem"}}]}},{"kind":"Field","name":{"kind":"Name","value":"programOffers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"dimension"},"value":{"kind":"StringValue","value":"state","block":false}},{"kind":"ObjectField","name":{"kind":"Name","value":"values"},"value":{"kind":"StringValue","value":"new","block":false}}]}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ProfileResponsesTableRow"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileProgramItem"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"FullProgramType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"timezone"}}]}},{"kind":"Field","name":{"kind":"Name","value":"scheduleItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"startTime"}},{"kind":"Field","name":{"kind":"Name","value":"endTime"}},{"kind":"Field","name":{"kind":"Name","value":"durationMinutes"}},{"kind":"Field","name":{"kind":"Name","value":"location"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ProfileResponsesTableRow"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ProfileResponseType"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"revisionCreatedAt"}},{"kind":"Field","name":{"kind":"Name","value":"canEdit"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"mode"},"value":{"kind":"EnumValue","value":"OWNER"}}]},{"kind":"Field","name":{"kind":"Name","value":"values"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"keyFieldsOnly"},"value":{"kind":"BooleanValue","value":true}}]},{"kind":"Field","name":{"kind":"Name","value":"dimensions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"keyDimensionsOnly"},"value":{"kind":"BooleanValue","value":true}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"dimension"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}]}},{"kind":"Field","name":{"kind":"Name","value":"value"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"title"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"lang"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]},{"kind":"Field","name":{"kind":"Name","value":"color"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"form"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"event"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}},{"kind":"Field","name":{"kind":"Name","value":"survey"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders/[orderId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders/[orderId]/page.tsx index 8007ad399..2751cc61a 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders/[orderId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/orders/[orderId]/page.tsx @@ -6,6 +6,7 @@ import { PaymentStatus } from "@/__generated__/graphql"; import Section from "@/components/Section"; import OrderHeader from "@/components/tickets/OrderHeader"; import ProductsTable from "@/components/tickets/ProductsTable"; +import SellerSection from "@/components/tickets/SellerSection"; import ViewContainer from "@/components/ViewContainer"; import { getOrder } from "@/services/tickets"; import { getTranslations } from "@/translations"; @@ -26,7 +27,7 @@ export const revalidate = 0; export default async function OrderPage(props: Props) { const params = await props.params; const { locale, eventSlug, orderId } = params; - const { order, event } = await getOrder(eventSlug, orderId); + const { order, event, seller } = await getOrder(eventSlug, orderId); const translations = getTranslations(locale); const t = translations.Tickets; @@ -51,6 +52,8 @@ export default async function OrderPage(props: Props) { + + {showPayButton && (
diff --git a/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx index 374437c33..88c4758d6 100644 --- a/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/profile/orders/[eventSlug]/[orderId]/page.tsx @@ -10,6 +10,7 @@ import SignInRequired from "@/components/errors/SignInRequired"; import ModalButton from "@/components/ModalButton"; import OrderHeader from "@/components/tickets/OrderHeader"; import ProductsTable from "@/components/tickets/ProductsTable"; +import SellerSection from "@/components/tickets/SellerSection"; import ViewContainer from "@/components/ViewContainer"; import ViewHeading from "@/components/ViewHeading"; import getPageTitle from "@/helpers/getPageTitle"; @@ -28,6 +29,7 @@ const query = graphql(` eticketsLink canPay canCancel + ticketsContactEmail products { title quantity @@ -38,6 +40,10 @@ const query = graphql(` event { slug name + organization { + name + businessId + } } } } @@ -129,6 +135,15 @@ export default async function ProfileOrderPage(props: Props) { messages={translations.Tickets} /> + + {order.canPay && (
diff --git a/kompassi-v2-frontend/src/components/tickets/SellerSection.tsx b/kompassi-v2-frontend/src/components/tickets/SellerSection.tsx new file mode 100644 index 000000000..0cf2321ee --- /dev/null +++ b/kompassi-v2-frontend/src/components/tickets/SellerSection.tsx @@ -0,0 +1,34 @@ +import Section from "@/components/Section"; +import type { Translations } from "@/translations/en"; + +interface Seller { + name: string; + email?: string | null; + businessId?: string | null; +} + +interface Props { + seller: Seller; + messages: Translations["Tickets"]["Order"]["attributes"]["seller"]; +} + +export default function SellerSection({ seller, messages: t }: Props) { + return ( +
+
+ {t.title}: {seller.name} +
+ {seller.email && ( +
+ {t.email}:{" "} + {seller.email} +
+ )} + {seller.businessId && ( +
+ {t.businessId}: {seller.businessId} +
+ )} +
+ ); +} diff --git a/kompassi-v2-frontend/src/services/tickets.ts b/kompassi-v2-frontend/src/services/tickets.ts index fa475d0e6..7f5db1e86 100644 --- a/kompassi-v2-frontend/src/services/tickets.ts +++ b/kompassi-v2-frontend/src/services/tickets.ts @@ -179,6 +179,11 @@ export interface GetOrderResponse { name: string; }; order: Order; + seller: { + name: string; + email: string | null; + businessId: string | null; + }; } export async function getOrder( diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 782738953..155531e5d 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -652,6 +652,11 @@ const translations = { createdAt: "Order date", eventName: "Event", totalPrice: "Total price", + seller: { + title: "Seller", + email: "Email", + businessId: "Business ID", + }, actions: "Actions", totalOrders: (numOrders: number) => ( <> diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 3f9760d80..47543fe6c 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -647,6 +647,11 @@ const translations: Translations = { createdAt: "Tilausaika", eventName: "Tapahtuma", totalPrice: "Yhteensä", + seller: { + title: "Myyjä", + email: "Sähköposti", + businessId: "Y-tunnus", + }, actions: "Toiminnot", totalOrders: (numOrders: number) => ( <> diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 3d55165c1..7fe0ae048 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -639,6 +639,11 @@ const translations: Translations = { createdAt: "Beställningsdatum", eventName: "Evenemang", totalPrice: "Totalpris", + seller: { + title: "Säljare", + email: "E-postadress", + businessId: "FO-nummer", + }, actions: "Funktioner", totalOrders: (numOrders: number) => ( <> diff --git a/kompassi/core/graphql/event_limited.py b/kompassi/core/graphql/event_limited.py index d2ee0803a..cae6d1cbe 100644 --- a/kompassi/core/graphql/event_limited.py +++ b/kompassi/core/graphql/event_limited.py @@ -4,6 +4,8 @@ from kompassi.core.models import Event from kompassi.graphql_api.utils import resolve_local_datetime_field +from .organization_limited import LimitedOrganizationType + class LimitedEventType(DjangoObjectType): class Meta: @@ -26,3 +28,9 @@ def resolve_timezone(event: Event, info): return event.timezone_name timezone = graphene.NonNull(graphene.String) + + @staticmethod + def resolve_organization(event: Event, info): + return event.organization + + organization = graphene.NonNull(LimitedOrganizationType) diff --git a/kompassi/core/graphql/organization_limited.py b/kompassi/core/graphql/organization_limited.py index b36642cfc..563836559 100644 --- a/kompassi/core/graphql/organization_limited.py +++ b/kompassi/core/graphql/organization_limited.py @@ -10,6 +10,7 @@ class Meta: fields = ( "slug", "name", + "business_id", ) timezone = graphene.NonNull(graphene.String) diff --git a/kompassi/core/migrations/0044_organization_business_id.py b/kompassi/core/migrations/0044_organization_business_id.py new file mode 100644 index 000000000..3fc46bf83 --- /dev/null +++ b/kompassi/core/migrations/0044_organization_business_id.py @@ -0,0 +1,21 @@ +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0043_emailverificationtoken_language_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="organization", + name="business_id", + field=models.CharField( + blank=True, + default="", + max_length=16, + verbose_name="Y-tunnus", + help_text="Finnish business ID (Y-tunnus), eg. 1234567-8.", + ), + ), + ] diff --git a/kompassi/core/models/organization.py b/kompassi/core/models/organization.py index b86ea8d53..e0952884f 100644 --- a/kompassi/core/models/organization.py +++ b/kompassi/core/models/organization.py @@ -48,6 +48,14 @@ class Organization(models.Model): help_text="Voi olla paikallinen (alkaa /-merkillä) tai absoluuttinen (alkaa http/https)", ) + business_id = models.CharField( + blank=True, + default="", + max_length=16, + verbose_name="Y-tunnus", + help_text="Finnish business ID (Y-tunnus), eg. 1234567-8.", + ) + panel_css_class = models.CharField( blank=True, max_length=255, diff --git a/kompassi/tickets_v2/graphql/order_profile.py b/kompassi/tickets_v2/graphql/order_profile.py index b204af8f0..e1c54cf39 100644 --- a/kompassi/tickets_v2/graphql/order_profile.py +++ b/kompassi/tickets_v2/graphql/order_profile.py @@ -69,3 +69,16 @@ def resolve_can_cancel(order: Order, info): graphene.Boolean, description=normalize_whitespace(resolve_can_cancel.__doc__ or ""), ) + + @staticmethod + def resolve_tickets_contact_email(order: Order, info): + """ + Contact email for the ticket seller (from the event's tickets meta). + """ + meta = order.event.tickets_v2_event_meta + return meta.contact_email if meta else "" + + tickets_contact_email = graphene.NonNull( + graphene.String, + description=normalize_whitespace(resolve_tickets_contact_email.__doc__ or ""), + ) diff --git a/kompassi/tickets_v2/models/receipt.py b/kompassi/tickets_v2/models/receipt.py index c0bcd7c4d..1bfe35f9a 100644 --- a/kompassi/tickets_v2/models/receipt.py +++ b/kompassi/tickets_v2/models/receipt.py @@ -190,10 +190,14 @@ def _get_event(cls, event_id: int): EVENT_CACHE.update( { event.id: event - for event in Event.objects.filter(ticketsv2eventmeta__isnull=False).only( + for event in Event.objects.filter(ticketsv2eventmeta__isnull=False) + .select_related("organization") + .only( "name", "slug", "timezone_name", + "organization__name", + "organization__business_id", ) } ) @@ -310,9 +314,11 @@ def body(self) -> str: case _: raise ValueError("Unknown receipt type") + organization = self.event.organization vars = dict( event_name=self.event.name, order_number=self.order_number, + order_date=self.order_date, products=self.products, total_price=self.total_price, vat_breakdown=self.vat_breakdown, @@ -322,6 +328,9 @@ def body(self) -> str: last_name=self.last_name, email=self.email, phone=self.phone, + seller_name=organization.name, + seller_email=self.meta.contact_email, + seller_business_id=organization.business_id, ) return render_to_string(template_name, vars) diff --git a/kompassi/tickets_v2/optimized_server/app.py b/kompassi/tickets_v2/optimized_server/app.py index 1a4432a1d..90271a227 100644 --- a/kompassi/tickets_v2/optimized_server/app.py +++ b/kompassi/tickets_v2/optimized_server/app.py @@ -149,6 +149,11 @@ async def get_order( "name": event.name, }, "order": order.model_dump(mode="json", by_alias=True), + "seller": { + "name": event.organization_name, + "email": event.contact_email or None, + "businessId": event.organization_business_id or None, + }, } diff --git a/kompassi/tickets_v2/optimized_server/models/event.py b/kompassi/tickets_v2/optimized_server/models/event.py index 4a62661fd..2d5bf3112 100644 --- a/kompassi/tickets_v2/optimized_server/models/event.py +++ b/kompassi/tickets_v2/optimized_server/models/event.py @@ -29,6 +29,10 @@ class Event(pydantic.BaseModel): paytrail_merchant: str paytrail_password: str + organization_name: str + contact_email: str + organization_business_id: str + cache: ClassVar[dict[str | int, Event]] = {} cache_refresh: ClassVar[Future[dict[str | int, Event]] | None] = None diff --git a/kompassi/tickets_v2/optimized_server/models/sql/get_events.sql b/kompassi/tickets_v2/optimized_server/models/sql/get_events.sql index 2eea3ad40..8bd3000cd 100644 --- a/kompassi/tickets_v2/optimized_server/models/sql/get_events.sql +++ b/kompassi/tickets_v2/optimized_server/models/sql/get_events.sql @@ -7,7 +7,10 @@ select m.terms_and_conditions_url_fi, m.terms_and_conditions_url_sv, coalesce(p.checkout_merchant, '') as paytrail_merchant, - coalesce(p.checkout_password, '') as paytrail_password + coalesce(p.checkout_password, '') as paytrail_password, + o.name as organization_name, + coalesce(m.contact_email, '') as contact_email, + o.business_id as organization_business_id from core_event e join tickets_v2_ticketsv2eventmeta m on (e.id = m.event_id) diff --git a/kompassi/tickets_v2/templates/tickets_v2_footer_en.eml b/kompassi/tickets_v2/templates/tickets_v2_footer_en.eml index 81322b835..e52543d82 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_footer_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_footer_en.eml @@ -3,5 +3,6 @@ Best regards On behalf of {{ event_name }} Kompassi Event Management System -Under Finnish tax regulations, the seller is not required to pay VAT -as it is a non-profit organization. +Seller: {{ seller_name }}{% if seller_email %} +Email: {{ seller_email }}{% endif %}{% if seller_business_id %} +Business ID: {{ seller_business_id }}{% endif %} diff --git a/kompassi/tickets_v2/templates/tickets_v2_footer_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_footer_fi.eml index fd51fc4a1..2b05209e6 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_footer_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_footer_fi.eml @@ -3,4 +3,6 @@ Ystävällisin terveisin {{ event_name }} -tapahtuman puolesta Kompassi-tapahtumanhallintajärjestelmä -Yleishyödyllisenä yhteisönä myyjä ei ole arvonlisäverovelvollinen. +Myyjä: {{ seller_name }}{% if seller_email %} +Sähköposti: {{ seller_email }}{% endif %}{% if seller_business_id %} +Y-tunnus: {{ seller_business_id }}{% endif %} diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml index 886ea522d..88e28aec5 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_en.eml @@ -2,6 +2,7 @@ Thank you for your order at the {{ event_name }} online shop! Your order number is {{ order_number|format_order_number }}. +Date of purchase: {{ order_date|date:"Y-m-d" }} We confirm the following products have been paid for: diff --git a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml index 04c08ccdb..c2d47e151 100644 --- a/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml +++ b/kompassi/tickets_v2/templates/tickets_v2_receipt_fi.eml @@ -2,6 +2,7 @@ Kiitos tilauksestasi {{ event_name }} -tapahtuman verkkokaupassa! Tilauksesi numero on {{ order_number|format_order_number }}. +Ostopäivä: {{ order_date|date:"d.m.Y" }} Vahvistamme maksetuiksi seuraavat lipputuotteet: From 4b7a09b324d5f2005644c7293558addcb850fc8f Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 14:50:32 +0300 Subject: [PATCH 24/31] chore(tracon-ry): Y-tunnus --- .../tracon_ry/management/commands/setup_tracon_ry.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/kompassi/organizations/tracon_ry/management/commands/setup_tracon_ry.py b/kompassi/organizations/tracon_ry/management/commands/setup_tracon_ry.py index 910280204..60ed1e704 100644 --- a/kompassi/organizations/tracon_ry/management/commands/setup_tracon_ry.py +++ b/kompassi/organizations/tracon_ry/management/commands/setup_tracon_ry.py @@ -40,13 +40,15 @@ def setup_core(self): Tracon ry:n yhdistysrekisteritunnus on 194.820. """.strip(), panel_css_class="panel-danger", + muncipality="Tampere", + public=True, ), ) - # v10 - self.organization.muncipality = "Tampere" - self.organization.public = True - self.organization.save() + # v44 + if not self.organization.business_id: + self.organization.business_id = "2886274-5" + self.organization.save(update_fields=["business_id"]) def setup_membership(self): (membership_admin_group,) = MembershipOrganizationMeta.get_or_create_groups(self.organization, ["admins"]) From ababb807ede3d6e808267de7685c55c5d9d7e5fc Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 14:52:27 +0300 Subject: [PATCH 25/31] chore(kotae-ry,ropecon-ry): Y-tunnus --- .../kotae_ry/management/commands/setup_kotae_ry.py | 10 ++++++---- .../ropecon_ry/management/commands/setup_ropecon_ry.py | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/kompassi/organizations/kotae_ry/management/commands/setup_kotae_ry.py b/kompassi/organizations/kotae_ry/management/commands/setup_kotae_ry.py index d216f8742..8e3d9b6c7 100644 --- a/kompassi/organizations/kotae_ry/management/commands/setup_kotae_ry.py +++ b/kompassi/organizations/kotae_ry/management/commands/setup_kotae_ry.py @@ -33,13 +33,15 @@ def setup_core(self): Kotae ry:n Y-tunnus on 3364741-7. """.strip(), + muncipality="Tampere", + public=True, ), ) - # v10 - self.organization.muncipality = "Tampere" - self.organization.public = True - self.organization.save() + # v44 + if not self.organization.business_id: + self.organization.business_id = "3364741-7" + self.organization.save(update_fields=["business_id"]) def setup_membership(self): (membership_admin_group,) = MembershipOrganizationMeta.get_or_create_groups(self.organization, ["admins"]) diff --git a/kompassi/organizations/ropecon_ry/management/commands/setup_ropecon_ry.py b/kompassi/organizations/ropecon_ry/management/commands/setup_ropecon_ry.py index 378f985e2..93c8bcbf8 100644 --- a/kompassi/organizations/ropecon_ry/management/commands/setup_ropecon_ry.py +++ b/kompassi/organizations/ropecon_ry/management/commands/setup_ropecon_ry.py @@ -26,6 +26,11 @@ def setup_core(self): ), ) + # v44 + if not self.organization.business_id: + self.organization.business_id = "1859716-7" + self.organization.save(update_fields=["business_id"]) + def setup_payments(self): PaymentsOrganizationMeta.objects.get_or_create( organization=self.organization, From 285cdd35e07b6067af45c3df3d96ab9462690a01 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 16:09:32 +0300 Subject: [PATCH 26/31] fix(tickets_v2): review fixes for VAT branch - VAT by month report: do not retroactively remove refunded orders from the month of the original sale; the VAT for that month may already have been filed. Include all ever-paid statuses, parameterized from PaymentStatus instead of a magic literal. Regression test included. - Seller email: contact_email is stored as "Name "; return the plain address in receipts, ticketsContactEmail and the order API so mailto: links work. - Product.vat_percentage: disallow negative values (folded into the unreleased 0008 migration). - Frontend: add missing space in Swedish vatIncluded, remove unused vatBreakdown translation key, make VAT rate required on the edit product form too. Co-Authored-By: Claude Fable 5 --- .../src/__generated__/graphql.ts | 2 +- .../[eventSlug]/products/[productId]/page.tsx | 1 + kompassi-v2-frontend/src/translations/en.tsx | 2 +- kompassi-v2-frontend/src/translations/fi.tsx | 1 - kompassi-v2-frontend/src/translations/sv.tsx | 3 +- kompassi/tickets_v2/graphql/order_profile.py | 3 +- .../migrations/0008_product_vat_percentage.py | 2 ++ kompassi/tickets_v2/models/product.py | 2 ++ kompassi/tickets_v2/models/receipt.py | 2 +- kompassi/tickets_v2/optimized_server/app.py | 2 +- .../optimized_server/models/event.py | 15 ++++++++ .../reports/sql/report_vat_by_month.sql | 2 +- kompassi/tickets_v2/reports/vat_by_month.py | 35 ++++++++++++++++--- kompassi/tickets_v2/tests.py | 28 +++++++++++++++ 14 files changed, 87 insertions(+), 13 deletions(-) diff --git a/kompassi-v2-frontend/src/__generated__/graphql.ts b/kompassi-v2-frontend/src/__generated__/graphql.ts index 0376f7ceb..791117428 100644 --- a/kompassi-v2-frontend/src/__generated__/graphql.ts +++ b/kompassi-v2-frontend/src/__generated__/graphql.ts @@ -2059,7 +2059,7 @@ export type ProfileOrderType = { /** Returns a link at which the user can view their electronic tickets. They need to be the owner of the order (or an admin) to access that link. Returns null if the order does not contain electronic tickets. */ products: Array; status: PaymentStatus; - /** Contact email for the ticket seller (from the event's tickets meta). */ + /** Contact email for the ticket seller (from the event's tickets meta). Plain email address without the display name. */ ticketsContactEmail: Scalars['String']['output']; totalPrice: Scalars['Decimal']['output']; }; diff --git a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx index df130799d..b58fde685 100644 --- a/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx +++ b/kompassi-v2-frontend/src/app/[locale]/[eventSlug]/products/[productId]/page.tsx @@ -189,6 +189,7 @@ export default async function AdminProductDetailPage(props: Props) { { slug: "vatPercentage", type: "SingleSelect", + required: true, choices: [ { slug: "0.00", title: "0%" }, { slug: "10.00", title: "10%" }, diff --git a/kompassi-v2-frontend/src/translations/en.tsx b/kompassi-v2-frontend/src/translations/en.tsx index 155531e5d..96bd8a9cf 100644 --- a/kompassi-v2-frontend/src/translations/en.tsx +++ b/kompassi-v2-frontend/src/translations/en.tsx @@ -1,4 +1,5 @@ import { JSX, ReactNode } from "react"; + const translations = { Common: { ok: "OK", @@ -535,7 +536,6 @@ const translations = { helpText: "The VAT rate that applies to this product. Prices are VAT-inclusive.", }, - vatBreakdown: "VAT breakdown", dragToReorder: "Drag to reorder", newProductQuota: { title: "Quota", diff --git a/kompassi-v2-frontend/src/translations/fi.tsx b/kompassi-v2-frontend/src/translations/fi.tsx index 47543fe6c..9a2586bc9 100644 --- a/kompassi-v2-frontend/src/translations/fi.tsx +++ b/kompassi-v2-frontend/src/translations/fi.tsx @@ -531,7 +531,6 @@ const translations: Translations = { helpText: "Tähän tuotteeseen sovellettava arvonlisäveroprosentti. Hinnat sisältävät ALV:n.", }, - vatBreakdown: "ALV-erittely", dragToReorder: "Vedä ja pudota järjestääksesi tuotteita", newProductQuota: { title: "Kiintiö", diff --git a/kompassi-v2-frontend/src/translations/sv.tsx b/kompassi-v2-frontend/src/translations/sv.tsx index 7fe0ae048..964b745a3 100644 --- a/kompassi-v2-frontend/src/translations/sv.tsx +++ b/kompassi-v2-frontend/src/translations/sv.tsx @@ -523,7 +523,6 @@ const translations: Translations = { helpText: "Den momssats som gäller för denna produkt. Priserna inkluderar moms.", }, - vatBreakdown: "Momsspecifikation", dragToReorder: "Dra för att sortera om", newProductQuota: { title: "Kvot", @@ -532,7 +531,7 @@ const translations: Translations = { }, }, serverAttributes: { - vatIncluded: (rate: string) => `inkl. moms${rate}%`, + vatIncluded: (rate: string) => `inkl. moms ${rate}%`, isAvailable: { untilFurtherNotice: "Tillgänglig tills vidare", untilTime: (formattedTime: string) => diff --git a/kompassi/tickets_v2/graphql/order_profile.py b/kompassi/tickets_v2/graphql/order_profile.py index e1c54cf39..5e2f6996a 100644 --- a/kompassi/tickets_v2/graphql/order_profile.py +++ b/kompassi/tickets_v2/graphql/order_profile.py @@ -74,9 +74,10 @@ def resolve_can_cancel(order: Order, info): def resolve_tickets_contact_email(order: Order, info): """ Contact email for the ticket seller (from the event's tickets meta). + Plain email address without the display name. """ meta = order.event.tickets_v2_event_meta - return meta.contact_email if meta else "" + return meta.plain_contact_email if meta else "" tickets_contact_email = graphene.NonNull( graphene.String, diff --git a/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py b/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py index 952a13198..59900f3ef 100644 --- a/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py +++ b/kompassi/tickets_v2/migrations/0008_product_vat_percentage.py @@ -2,6 +2,7 @@ from decimal import Decimal +import django.core.validators from django.db import migrations, models @@ -19,6 +20,7 @@ class Migration(migrations.Migration): default=Decimal("0"), help_text="VAT percentage applied to this product. Prices are inclusive of VAT.", max_digits=4, + validators=[django.core.validators.MinValueValidator(Decimal(0))], ), ), ] diff --git a/kompassi/tickets_v2/models/product.py b/kompassi/tickets_v2/models/product.py index 6a7447f56..40132c9aa 100644 --- a/kompassi/tickets_v2/models/product.py +++ b/kompassi/tickets_v2/models/product.py @@ -6,6 +6,7 @@ import pydantic from django.conf import settings +from django.core.validators import MinValueValidator from django.db import connection, models from django.http import HttpRequest from django.utils.timezone import now @@ -93,6 +94,7 @@ class Product(models.Model): max_digits=4, decimal_places=2, default=Decimal("0"), + validators=[MinValueValidator(Decimal(0))], help_text="VAT percentage applied to this product. Prices are inclusive of VAT.", ) title = models.TextField() diff --git a/kompassi/tickets_v2/models/receipt.py b/kompassi/tickets_v2/models/receipt.py index 1bfe35f9a..32e0b21c7 100644 --- a/kompassi/tickets_v2/models/receipt.py +++ b/kompassi/tickets_v2/models/receipt.py @@ -329,7 +329,7 @@ def body(self) -> str: email=self.email, phone=self.phone, seller_name=organization.name, - seller_email=self.meta.contact_email, + seller_email=self.meta.plain_contact_email, seller_business_id=organization.business_id, ) return render_to_string(template_name, vars) diff --git a/kompassi/tickets_v2/optimized_server/app.py b/kompassi/tickets_v2/optimized_server/app.py index 90271a227..5d3b5964a 100644 --- a/kompassi/tickets_v2/optimized_server/app.py +++ b/kompassi/tickets_v2/optimized_server/app.py @@ -151,7 +151,7 @@ async def get_order( "order": order.model_dump(mode="json", by_alias=True), "seller": { "name": event.organization_name, - "email": event.contact_email or None, + "email": event.plain_contact_email or None, "businessId": event.organization_business_id or None, }, } diff --git a/kompassi/tickets_v2/optimized_server/models/event.py b/kompassi/tickets_v2/optimized_server/models/event.py index 2d5bf3112..ab532a8b6 100644 --- a/kompassi/tickets_v2/optimized_server/models/event.py +++ b/kompassi/tickets_v2/optimized_server/models/event.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re from asyncio import Future, ensure_future from functools import cached_property from pathlib import Path @@ -12,6 +13,10 @@ if TYPE_CHECKING: from psycopg import AsyncConnection +# Keep in sync with kompassi.core.models.contact_email_mixin.CONTACT_EMAIL_RE +# (not imported to keep the optimized server free of Django imports) +CONTACT_EMAIL_RE = re.compile(r"(?P.+) <(?P.+@.+\..+)>") + class Event(pydantic.BaseModel): id: int @@ -76,6 +81,16 @@ async def _do_refresh_cache(cls, db: AsyncConnection): def model_dump(self, *args, **kwargs) -> Any: raise NotImplementedError("contains secrets, please don't") + @property + def plain_contact_email(self) -> str: + """ + contact_email is stored in the "Name Surname " format. + Return the plain email address only (or the raw value if it is not in that format). + """ + if match := CONTACT_EMAIL_RE.match(self.contact_email): + return match.group("email") + return self.contact_email + @cached_property def provider(self): from ..providers.null import NullProvider diff --git a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql index 2e2c8d3bf..70f28aa8f 100644 --- a/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql +++ b/kompassi/tickets_v2/reports/sql/report_vat_by_month.sql @@ -16,7 +16,7 @@ from join tickets_v2_product p on p.id = pd.product_id::int where o.event_id = %(event_id)s - and o.cached_status = 3 + and o.cached_status = any(%(paid_statuses)s) and pd.quantity::int > 0 and p.vat_percentage > 0 group by 1, 2 diff --git a/kompassi/tickets_v2/reports/vat_by_month.py b/kompassi/tickets_v2/reports/vat_by_month.py index a6f493858..c798a9025 100644 --- a/kompassi/tickets_v2/reports/vat_by_month.py +++ b/kompassi/tickets_v2/reports/vat_by_month.py @@ -11,6 +11,7 @@ from kompassi.reports.models.enums import TypeOfColumn from kompassi.reports.models.report import Report +from ..optimized_server.models.enums import PaymentStatus from ..optimized_server.utils.formatting import format_vat_rate SQL_DIR = Path(__file__).parent / "sql" @@ -23,12 +24,31 @@ MONTH_COLUMN_TITLE = dict(fi="Kuukausi", en="Month", sv="Månad") TOTAL_COLUMN_TITLE = dict(fi="Yhteensä", en="Total", sv="Totalt") FOOTER = dict( - fi="Vain maksetut tilaukset on laskettu mukaan. Hyvitykset eivät sisälly raporttiin.", - en="Only paid orders are included. Refunds are not reflected in this report.", - sv="Endast betalda beställningar ingår. Återbetalningar visas inte i rapporten.", + fi=( + "Vain maksetut tilaukset on laskettu mukaan. Hyvitetyt tilaukset näkyvät " + "alkuperäisen myyntikuukauden kohdalla; hyvityksiä ei vähennetä." + ), + en=( + "Only paid orders are included. Refunded orders are shown in the month of " + "the original sale; refunds are not subtracted." + ), + sv=( + "Endast betalda beställningar ingår. Återbetalda beställningar visas under " + "den ursprungliga försäljningsmånaden; återbetalningar dras inte av." + ), ) CENT = Decimal("0.01") +# Orders in these statuses have been paid at some point. A later refund must not +# retroactively remove the sale from the month it was made in, as the VAT for +# that month may already have been filed. +EVER_PAID_STATUSES = [ + PaymentStatus.PAID, + PaymentStatus.REFUND_REQUESTED, + PaymentStatus.REFUND_FAILED, + PaymentStatus.REFUNDED, +] + def _vat_column_title(rate: Decimal) -> dict[str, str]: return {lang: f"{format_vat_rate(rate, lang)}%" for lang in ("fi", "en", "sv")} @@ -40,7 +60,14 @@ class VatByMonth: @classmethod def report(cls, event: Event, lang: str = DEFAULT_LANGUAGE) -> Report: with connection.cursor() as cursor: - cursor.execute(cls.query, dict(event_id=event.id, event_timezone=event.timezone_name)) + cursor.execute( + cls.query, + dict( + event_id=event.id, + event_timezone=event.timezone_name, + paid_statuses=[status.value for status in EVER_PAID_STATUSES], + ), + ) raw_rows = cursor.fetchall() vat_rates: list[Decimal] = sorted({row[1] for row in raw_rows}) diff --git a/kompassi/tickets_v2/tests.py b/kompassi/tickets_v2/tests.py index 9c7f137ef..6dbfeb913 100644 --- a/kompassi/tickets_v2/tests.py +++ b/kompassi/tickets_v2/tests.py @@ -444,6 +444,34 @@ def test_vat_by_month_report_basic(vat_report_event: Event): assert grand_total == pytest.approx(79.00) +@pytest.mark.django_db +def test_vat_by_month_report_refund_does_not_change_history(vat_report_event: Event): + """ + Once an order has been paid, its VAT belongs to the month of the sale even if + the order is later refunded — the VAT for that month may already have been + filed, so the report must not change retroactively. (The footer tells the + reader that refunds are not subtracted.) + """ + product = Product.objects.create( + event=vat_report_event, + title="Standard", + description="", + price=Decimal("125.50"), + vat_percentage=Decimal("25.50"), + ) + + _make_order(vat_report_event, datetime(2026, 1, 15, 12, 0, tzinfo=UTC), {product.id: 1}) + for status in ( + PaymentStatus.REFUND_REQUESTED, + PaymentStatus.REFUND_FAILED, + PaymentStatus.REFUNDED, + ): + _make_order(vat_report_event, datetime(2026, 1, 20, 12, 0, tzinfo=UTC), {product.id: 1}, status=status) + + report = VatByMonth.report(vat_report_event, "en") + assert report.rows == [["2026-01", 4 * 25.50, 4 * 25.50]] + + @pytest.mark.django_db def test_vat_by_month_report_timezone_boundary(vat_report_event: Event): """ From 536733e5bcd25f5fd891e661bb4cbbaac78b4564 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 16:11:59 +0300 Subject: [PATCH 27/31] chore(deps): backend deps --- uv.lock | 333 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 167 insertions(+), 166 deletions(-) diff --git a/uv.lock b/uv.lock index 392c94681..a5d5f328d 100644 --- a/uv.lock +++ b/uv.lock @@ -28,7 +28,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.14.0" +version = "3.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -39,49 +39,49 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ee/ab/93ce242f899b68c51b0578c027aafa791ab3614cb9345fa5d37b5f5c8e3e/aiohttp-3.14.0.tar.gz", hash = "sha256:2882de819734c715fd1b9c11c97e09fa020d14438203d1d354d8ed1702791c9b", size = 7940674, upload-time = "2026-06-01T19:41:02.763Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/28/03/5f36ab196a88ba5e9648ae5643e6531e67a3a8c0e96f9c6510ff41540fec/aiohttp-3.14.0-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:363ef9e91014e7891679bfb2ac0a7c6ea93435dbbfd10ecf41b9f06fcf506c5f", size = 503330, upload-time = "2026-06-01T19:39:18.195Z" }, - { url = "https://files.pythonhosted.org/packages/2c/ce/8b49ec2f30f68e02f314f4832186cd45e583360a5a386058be36855d23b6/aiohttp-3.14.0-cp314-cp314-android_24_x86_64.whl", hash = "sha256:884a4edbdad77be9d0ef36142c8b504351b170df0bf62b51e784fadabf311c42", size = 509822, upload-time = "2026-06-01T19:39:20.396Z" }, - { url = "https://files.pythonhosted.org/packages/1a/fe/6edbf5d39bf29322b6816365b17ed8ede4dace164a3aea1abcd30110eb78/aiohttp-3.14.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:70ea956f6cc4a37620966b56c2e205d88ca3e6d85ec063277e414b1035cddad3", size = 483329, upload-time = "2026-06-01T19:39:22.607Z" }, - { url = "https://files.pythonhosted.org/packages/1b/5a/fae531bdbc6456fb6241f46b7b81e4d8a0dd3fc09118a0055dc7141ac1ec/aiohttp-3.14.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:ea3b9806c89f61da22fddf1f12dd524fb368e5e28f1261fbdafe5c3cd8ce893b", size = 489502, upload-time = "2026-06-01T19:39:24.881Z" }, - { url = "https://files.pythonhosted.org/packages/36/f4/48a7b0414db7fed77a03d5dde34508c026afd83510ab6bca08c313855776/aiohttp-3.14.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:a071be341c2bd9b0188e62d173509f024e0a35b1c342c53c50f8daaeda8c3bd8", size = 497357, upload-time = "2026-06-01T19:39:27.197Z" }, - { url = "https://files.pythonhosted.org/packages/75/75/e85a13a370acc007fca5feb1fd1b88ac2d8426e6dadd625479b7cadd55a3/aiohttp-3.14.0-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:198cfe61bf253b19da1fb3e0fa122249dc4f14c12709493fed8054aa0411cc76", size = 750898, upload-time = "2026-06-01T19:39:29.563Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e4/3d637f800c724eff0e2bed64df72557444482366fd0a35b0cec0e6968f6c/aiohttp-3.14.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9dc203d6ce6b9106d54e2a93f41dfdfebfbca2d99962ba503bfd3e5921a6549e", size = 506986, upload-time = "2026-06-01T19:39:31.872Z" }, - { url = "https://files.pythonhosted.org/packages/1d/df/35161f3598bf7501d2b2a805b41ab4f45a2e34150c421bcb4ef8c0d281a7/aiohttp-3.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:9e19d17ab02bf16832a2c8c0d55a486792c5b1645665652ee9531aebcc30cb72", size = 508033, upload-time = "2026-06-01T19:39:34.137Z" }, - { url = "https://files.pythonhosted.org/packages/e5/39/b36e5d3d31e850fb4691dd3e941684ac490a2559249f6fa634b6b0fdf020/aiohttp-3.14.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d925fba0c14d5b498a8028b0107beebdfd16c5d48d702ff54f879cb017aaaca3", size = 1746213, upload-time = "2026-06-01T19:39:36.654Z" }, - { url = "https://files.pythonhosted.org/packages/b1/28/24e1409e605a9aa5d84abe0e2acb365354b70ae56d40948101cabe3341ab/aiohttp-3.14.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d33e61021222ce7f9792bcac870d6f58d8adfceda33ab857b01264f4560f2c5f", size = 1705862, upload-time = "2026-06-01T19:39:38.968Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d0/e5eb3ff1daeaf644c7e36a957517672494122628e067c38b263fa04eda77/aiohttp-3.14.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:44eca38755d0105bb32f47d085f5dd449846a449e1245fc105889e3279dcf8e3", size = 1798909, upload-time = "2026-06-01T19:39:41.334Z" }, - { url = "https://files.pythonhosted.org/packages/d3/ba/8943f906f0570342886ababb9a722a44e360f786a028c5e0b0e29e3f735b/aiohttp-3.14.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f13087e06f68fea4941c21a0c541c00553aa16e4f8fd7bbe2b198df761e964d6", size = 1868892, upload-time = "2026-06-01T19:39:43.807Z" }, - { url = "https://files.pythonhosted.org/packages/3a/05/27df32c844b2156e1675a8d8ec22d963e3c8ba469ed7ceb1863320c7b521/aiohttp-3.14.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ff82be7f1ef73634cb77890a770743239bc3d487b848669be1c599889336dc0a", size = 1751659, upload-time = "2026-06-01T19:39:46.398Z" }, - { url = "https://files.pythonhosted.org/packages/7f/62/da182e5910ab912b2e88aa919b61a16046a37a95714a5795b02eb57b2d18/aiohttp-3.14.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a150c0875ac8fd87f1c398650841308a30d65facf7416b12dbdb9cfdcbe5a48c", size = 1578775, upload-time = "2026-06-01T19:39:48.902Z" }, - { url = "https://files.pythonhosted.org/packages/66/e3/53c67097e8a5ce98625e91e3fa7f43c9c6940de680345d03b3509a72a078/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:edc01ea4e1ec5a1649a28866262bf24195889ff7b27bdd947029a6086741de9b", size = 1710090, upload-time = "2026-06-01T19:39:51.392Z" }, - { url = "https://files.pythonhosted.org/packages/dd/55/0e2732ca598c7a4dfe8a775662376d0ca2977cb1030e48386d4da5d9a456/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:540632bf882ff8fc88f2e1697be0761578e89e0d79fb4a8a6d65dc5da7e729d4", size = 1715016, upload-time = "2026-06-01T19:39:53.807Z" }, - { url = "https://files.pythonhosted.org/packages/5a/96/f0b73730798c9ca525afc30b39f1f81bbe24e245d9654c54d3b39d63212d/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:860a86bc2c80237f5dff52edcf427e10a8d8352271fd84845429a3e60199e02c", size = 1763810, upload-time = "2026-06-01T19:39:56.31Z" }, - { url = "https://files.pythonhosted.org/packages/71/cc/11acb6c4518f448323405a7312b6f255d0f974a34373ad1db7633c4aadc8/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5cbd50e6a50d6b99283a826b18cbdebf65b0797689a7535cb0e9dd37be0f63c3", size = 1573064, upload-time = "2026-06-01T19:39:58.718Z" }, - { url = "https://files.pythonhosted.org/packages/de/2d/28c31dde0a7dc98c0ee7d0da2ddcec3f7688c4fc131e5989e278d0c03c0a/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:20144819e99db593e22bbd2f3f2691a5e149f879142d6b8670254708853ff4fb", size = 1775765, upload-time = "2026-06-01T19:40:01.195Z" }, - { url = "https://files.pythonhosted.org/packages/b8/69/155c4ef3aec96417d47024800472b33b16c5d8a665371dcd044c2afdf25d/aiohttp-3.14.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:26b6d79aa54cb4ed50cc7d41ed14e99e0f1fc8e7c2d42f2e05b37aea897b2b52", size = 1733716, upload-time = "2026-06-01T19:40:03.631Z" }, - { url = "https://files.pythonhosted.org/packages/5f/44/6126116fd8a316b712bb615660b855c78466bb67ba1bb1742427eafcf7ac/aiohttp-3.14.0-cp314-cp314-win32.whl", hash = "sha256:106ed074a856f3e21d186b8579e2c8afb6da598e267cdaab01059e13db2fc44d", size = 453684, upload-time = "2026-06-01T19:40:06.277Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d7/eff4c58a88c5cac5e38b55f44fb8a6d3929c3cbd77356e383e094d3220bd/aiohttp-3.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f770846edae8f00ecc57af825bce811f787f87a7dcf0e90d191790efe5b31f7", size = 481758, upload-time = "2026-06-01T19:40:08.653Z" }, - { url = "https://files.pythonhosted.org/packages/d7/ed/17b5bd9fbcb46e688f02e572f517754a9a75831e7b54702f027761dc4fa5/aiohttp-3.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:acf1581c4f21ed4b80a2dded504d87b055a071a84d5737ea966435f768275ac6", size = 450557, upload-time = "2026-06-01T19:40:11.03Z" }, - { url = "https://files.pythonhosted.org/packages/12/34/6180103ce9aabc8ebff3f7bb55a1228ffe60f61042823031d9692cb7b101/aiohttp-3.14.0-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:6aa1a40f9cbb3da9f80714c5966b8946c21e6a2530d809b9498b33161e3c8733", size = 787878, upload-time = "2026-06-01T19:40:13.401Z" }, - { url = "https://files.pythonhosted.org/packages/92/e9/08954a40e8b7baa3d8beadd2b074b186e9b1e9c8ddabc288678a6265de50/aiohttp-3.14.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:b62af5a8cc96a194eaa01a9ed7b34a3ffa58d3d8daaa1a0d7a749353ad12d228", size = 524400, upload-time = "2026-06-01T19:40:15.972Z" }, - { url = "https://files.pythonhosted.org/packages/08/6a/b5965a634ac4d5ba99a463314cf4ab214ca073fcdc38a15e0294273701fc/aiohttp-3.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6eb63b1417efaf7d1002a6ad034a40d44376afcc16508a57f8e74b49ad26a095", size = 527904, upload-time = "2026-06-01T19:40:18.28Z" }, - { url = "https://files.pythonhosted.org/packages/06/b4/932bcdd850c354d9bcca30f360e475d7852e30413fbbd44b182782ed5432/aiohttp-3.14.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c20b9ad156a79eb97be5cf9e069eec01d2f0dc8472ffbd75299a8b2d4c2cbbde", size = 1912162, upload-time = "2026-06-01T19:40:20.825Z" }, - { url = "https://files.pythonhosted.org/packages/c6/85/ce79bab0310d2e3fd2d7bc7e44412abeff7c8338f8a21dd0f2f1714989e5/aiohttp-3.14.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:40ae7b0642c25632c7eabc4a04754012691864d2a1b93becf7cddb76027b838a", size = 1778813, upload-time = "2026-06-01T19:40:23.726Z" }, - { url = "https://files.pythonhosted.org/packages/05/54/ba62ac2d1bc87e010aad23751e383b8794e45d931df67677313a2da78823/aiohttp-3.14.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:95f5217e76a046b9f228a101717ef8d42b1eb3d9d196d15202db5bf41df88936", size = 1899969, upload-time = "2026-06-01T19:40:26.406Z" }, - { url = "https://files.pythonhosted.org/packages/dc/82/7cc7907725d83a19f31551334061e1ab8e108b1d7ac52632a2a844a4acb5/aiohttp-3.14.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1a4a9f17e85b80878c176695c1998c790e83731d8271881e5d356488652a1f9e", size = 1991771, upload-time = "2026-06-01T19:40:29.061Z" }, - { url = "https://files.pythonhosted.org/packages/d0/1c/a57de71a4508c93a830b77c28af3d08cd97f606dedfc6b94275347744508/aiohttp-3.14.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:145262119b07d7f95abc1839add35ba2bfc84551d4b4660ca11542c0b215455b", size = 1868606, upload-time = "2026-06-01T19:40:31.843Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ae/3839726cd49150a53ed340cc24ce5ba09d4c2117020ef9d45542bec5eb2f/aiohttp-3.14.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:49a33ded29b0b2fa7a367a02cf0fb89af602bb87542a16177ec8ce1c9c51d12a", size = 1665437, upload-time = "2026-06-01T19:40:35.01Z" }, - { url = "https://files.pythonhosted.org/packages/35/1e/c237923232c7da7f0392ea25d89fc5e60c0e93f685f4ebca8e7bcdd5271c/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2cc736a9c9fc2bc4dd71fd404815741b6573df27c3f985948ec4076989ac57de", size = 1834090, upload-time = "2026-06-01T19:40:37.733Z" }, - { url = "https://files.pythonhosted.org/packages/98/02/a5a7a2524f92d3911761b405a7c067c751891942144adc13e2ad79611e39/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:b4141a3e5342ee3053a9cab54d25b64ed28289c1041e4c54b3d99839314d90ce", size = 1816907, upload-time = "2026-06-01T19:40:40.46Z" }, - { url = "https://files.pythonhosted.org/packages/fa/76/a8b9f0d09234d516af9f2d7dd715557f33b5da3b0b56ead41d1170e86e3c/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:e30871b2d58996cb81aac52d2b1d15ac05257131ef0f90f18c2115a380fbfe7c", size = 1840382, upload-time = "2026-06-01T19:40:43.48Z" }, - { url = "https://files.pythonhosted.org/packages/c9/8e/140e715a0a4bbc211979ea30ec8396ad2ed5bf90ab87d8058fc4668b1923/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:667b881d083ccae3900ea5a241e17e5007ca78844c53ed389bb63d48f729d9c7", size = 1659497, upload-time = "2026-06-01T19:40:46.265Z" }, - { url = "https://files.pythonhosted.org/packages/10/c7/7ba5de8af9650b9767b063c675427b8685f43fa7ce563673a7bc3af60f08/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:b584dfe615d151e9b8f0a8ecb3aee6147f2927ec5b95ba25fe621f5377510928", size = 1870829, upload-time = "2026-06-01T19:40:49.583Z" }, - { url = "https://files.pythonhosted.org/packages/cc/bc/2aaab2f85cadb26ea59c091fa2b8e370d625154b5c14b478f1b489d07551/aiohttp-3.14.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6199707cc40e0e9cd39c36fbc97bec416c704e1d0ddce03412bb3b3e6a90ccd0", size = 1832281, upload-time = "2026-06-01T19:40:52.303Z" }, - { url = "https://files.pythonhosted.org/packages/39/98/31b9ad9fbc01f0075ee7221002df5fd2d10b647f451ca5f30edc802d9dd6/aiohttp-3.14.0-cp314-cp314t-win32.whl", hash = "sha256:a8d93334d4961c9d566b1f046c81dee475b7c21eb730728d38237bfa70d1c8e6", size = 490597, upload-time = "2026-06-01T19:40:54.937Z" }, - { url = "https://files.pythonhosted.org/packages/59/1f/299b21441c8de42ff70fddc7cfe65e92f810abcf740739a09b56f7835364/aiohttp-3.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:2d2ffe9b614f50f069068b3b52e73414e4107fc10b7efc939a76acff9251fdd2", size = 525789, upload-time = "2026-06-01T19:40:57.306Z" }, - { url = "https://files.pythonhosted.org/packages/70/11/7f83fcba9ee05d4c54d61b3f8104da0d43a59adac44dd28effc0c9a10422/aiohttp-3.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:7a3fc4358e65826c515350f199c210de747cf669998211b1ee6c2e46de364b24", size = 467399, upload-time = "2026-06-01T19:40:59.993Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/82/78/8ea7308cac6934de8c74a14f3d5f65d1c89287426688be79538d0e5c013d/aiohttp-3.14.1.tar.gz", hash = "sha256:307f2cff90a764d329e77040603fa032db89c5c24fdad50c4c15334cba744035", size = 7955794, upload-time = "2026-06-07T21:09:35.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/a1/5fafa04e1ca91ddb47608699d60649c1c6db3cf41c99e78fc4056f9513db/aiohttp-3.14.1-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7c106c26852ca1c2047c6b80384f17100b4e439af276f21ef3d4e2f450ae7e15", size = 508531, upload-time = "2026-06-07T21:08:02.093Z" }, + { url = "https://files.pythonhosted.org/packages/fa/2e/bfa02f699d87ffc86d5959270b28f1cb410add3ccaced8ed2e0b8a5238fc/aiohttp-3.14.1-cp314-cp314-android_24_x86_64.whl", hash = "sha256:20205f7f5ade7aaec9f4b500549bbc071b046453aed72f9c06dcab87896a83e8", size = 514718, upload-time = "2026-06-07T21:08:04.476Z" }, + { url = "https://files.pythonhosted.org/packages/85/a5/9594ad6289eebbc97d167c44213d557807f90e59115caad24de21ad2c3b1/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:62a759436b29e677181a9e76bab8b8f689a29cb9c535f45f7c48c9c830d3f8c3", size = 487918, upload-time = "2026-06-07T21:08:06.377Z" }, + { url = "https://files.pythonhosted.org/packages/b4/61/16a32c36c3c49edec122a3dc811f2057df2f94d3b14aa107c8017d981618/aiohttp-3.14.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:2964cbf553df4d7a57348da44d961d871895fc1ee4e8c322b2a95612c7b17fba", size = 494014, upload-time = "2026-06-07T21:08:08.263Z" }, + { url = "https://files.pythonhosted.org/packages/9b/89/3ebcf96ed99c05bec9c434aaac6963fd3cbab4a786ae739908a144d9ce44/aiohttp-3.14.1-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:237651caadc3a59badd39319c54642b5299e9cc98a3a194310e55d5bb9f5e397", size = 502398, upload-time = "2026-06-07T21:08:10.244Z" }, + { url = "https://files.pythonhosted.org/packages/fd/3d/b74870a0c2d40c355928cd5b96c7a11fa821b8a40fc41365e64479b151fb/aiohttp-3.14.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:896e12dfdbbab9d8f7e16d2b28c6769a60126fa92095d1ebf9473d02593a2448", size = 758018, upload-time = "2026-06-07T21:08:12.447Z" }, + { url = "https://files.pythonhosted.org/packages/d3/66/f42f5c984d99e49c6cff5f26f590750f2e2f7ef1fcfb99966ab5be1b632e/aiohttp-3.14.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d03f281ed22579314ba00821ce20115a7c0ac430660b4cc05704a3f818b3e004", size = 512462, upload-time = "2026-06-07T21:08:14.624Z" }, + { url = "https://files.pythonhosted.org/packages/e9/a7/248e1aebe0c7810b0271e021a0f2a5eb6e78a051885b3c9df49f42a5802d/aiohttp-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:07eabb979d236335fed927e137a928c9adfb7df3b9ec7aa31726f133a62be983", size = 512824, upload-time = "2026-06-07T21:08:16.572Z" }, + { url = "https://files.pythonhosted.org/packages/26/97/2aa0e5ba0727dc3bd5aaebb7ccbc510f7dfb7fb961ec87497cd496635ab1/aiohttp-3.14.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4fe1f1087cbadb280b5e1bb054a4f00d1423c74d6626c5e48400d871d34ecefe", size = 1749898, upload-time = "2026-06-07T21:08:18.635Z" }, + { url = "https://files.pythonhosted.org/packages/00/8d/e97f6c96c891d457c8479d92a514ba194d0412f981d72c70341ee18488ed/aiohttp-3.14.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:367a9314fdc79dab0fac96e216cb41dd73c85bdca85306ce8999118ba7e0f333", size = 1710114, upload-time = "2026-06-07T21:08:20.892Z" }, + { url = "https://files.pythonhosted.org/packages/6f/e6/aa8d7e863048c8fceb5cd6ce74017311cec3ead07847387e12265fb4444e/aiohttp-3.14.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a24f677ebe83749039e7bdf862ff0bbb16818ae4193d4ef96505e269375bcce0", size = 1802541, upload-time = "2026-06-07T21:08:23.044Z" }, + { url = "https://files.pythonhosted.org/packages/83/a8/72193137de57fda4ebfae4563182d082c8856e3b6e9871d0b46f028fb369/aiohttp-3.14.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c83afe0ba876be7e943d2e0ba645809ad441575d2840c895c21ee5de93b9377a", size = 1875776, upload-time = "2026-06-07T21:08:25.288Z" }, + { url = "https://files.pythonhosted.org/packages/a0/18/938441025db6769a3464596b2410af3afde0b21eb2f204c6f766f68af4bd/aiohttp-3.14.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:634e385930fb6d2d479cf3aa66515955863b77a5e3c2b5894ca259a25b308602", size = 1760329, upload-time = "2026-06-07T21:08:27.363Z" }, + { url = "https://files.pythonhosted.org/packages/60/29/bf2496b4065e76e09fe48015aaffe5ce161d8f089b06ac6982070f653076/aiohttp-3.14.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:eeea07c4397bbc57719c4eed8f9c284874d4f175f9b6d57f7a1546b976d455ca", size = 1587293, upload-time = "2026-06-07T21:08:29.805Z" }, + { url = "https://files.pythonhosted.org/packages/49/a2/2136674d52123b1354bd05dd5753c318db47dc0c927cc70b27bab3755456/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:335c0cc3e3545ce98dcb9cfcb836f40c3411f43fa03dab757597d80c89af8a35", size = 1714756, upload-time = "2026-06-07T21:08:32.094Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b9/e5fd2e6f915503081c0f9b1e8540947037929c70c191da2e4d54b31a21a1/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:ae6be797afdef264e8a84864a85b196ca06045586481b3df8a967322fd2fa844", size = 1721052, upload-time = "2026-06-07T21:08:34.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/5a/2833e324a2263e104e31e2e91bc5bbee81bc499afd32203faee048a883f0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:8560b4d712474335d08907db7973f71912d3a9a8f1dee992ec06b5d2fe359496", size = 1766888, upload-time = "2026-06-07T21:08:36.95Z" }, + { url = "https://files.pythonhosted.org/packages/57/fa/dea6511870913162f3b2e8c42a7614eb203a4540b8c2da43e0bfb0548f3c/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2b7edd08e0a5deb1e8564a2fcd8f4561014a3f05252334671bbf55ddd47db0e5", size = 1581679, upload-time = "2026-06-07T21:08:39.292Z" }, + { url = "https://files.pythonhosted.org/packages/14/bd/3cf0d55e71784b33534e9710a67d382d900598b4787fbce6cc7317f8c42a/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:b6ff7fcee63287ae57b5df3e4f5957ce032122802509246dec1a5bcc55904c95", size = 1782021, upload-time = "2026-06-07T21:08:41.407Z" }, + { url = "https://files.pythonhosted.org/packages/c1/af/14bb5843eccbe234f4dfb78ab73e549d99727247e62ae5d62cbd22eaf5b0/aiohttp-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6ffbb2f4ec1ceaff7e07d43922954da26b223d188bf30658e561b98e23089444", size = 1742574, upload-time = "2026-06-07T21:08:43.795Z" }, + { url = "https://files.pythonhosted.org/packages/f2/1e/fbeb7af9210a67ac0f9c9bec0f8f4568497924e33137a3d5b48e1cf85f3f/aiohttp-3.14.1-cp314-cp314-win32.whl", hash = "sha256:a9875b46d910cff3ea2f5962f9d266b465459fe634e22556ab9bd6fc1192eea0", size = 457773, upload-time = "2026-06-07T21:08:46.168Z" }, + { url = "https://files.pythonhosted.org/packages/f0/2b/13e8d741a9ec5db7d900c060554cf8352ab85e44e2a4469ebb9d377bda17/aiohttp-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:af8b4b81a960eeaf1234971ac3cd0ba5901f3cd42eae42a46b4d089a8b492719", size = 485001, upload-time = "2026-06-07T21:08:48.401Z" }, + { url = "https://files.pythonhosted.org/packages/df/30/491acfa2c4d6c3ff59c49a14fc1b50be3241e25bbb0c84c09e2da4d11395/aiohttp-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:cf4491381b1b57425c315a56a439251b1bdac07b2275f19a8c44bc57744532ec", size = 453809, upload-time = "2026-06-07T21:08:50.7Z" }, + { url = "https://files.pythonhosted.org/packages/34/e3/19dbe1a1f4cc6230eb9e314de7fe68053b0992f9302b27d12141a0b5db53/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:819c054312f1af92947e6a55883d1b66feefab11531a7fc45e0fb9b63880b5c2", size = 793320, upload-time = "2026-06-07T21:08:52.775Z" }, + { url = "https://files.pythonhosted.org/packages/7f/20/1b7182219ba1b108430d6e4dc53d25ae02dcfcf5a045b33af4e8c5167527/aiohttp-3.14.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:10ee9c1753a8f706345b22496c79fbddb5be0599e0823f3738b1534058e25340", size = 529077, upload-time = "2026-06-07T21:08:55Z" }, + { url = "https://files.pythonhosted.org/packages/b9/c8/14ce60ec31a2e5f5274bb17d383a6f7a3aabca31ac04eee05585bbadab16/aiohttp-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1601cc37baf5750ccacae618ec2daf020769581695550e3b654a911f859c563d", size = 532476, upload-time = "2026-06-07T21:08:57.176Z" }, + { url = "https://files.pythonhosted.org/packages/7e/02/9ac85e081e53da2e061b02fa7758fe0a12d17b8ce2d1f5e6c7cb76730328/aiohttp-3.14.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4d6e0ac9da31c9c04c84e1c0182ad8d6df35965a85cae29cd71d089621b3ae94", size = 1922347, upload-time = "2026-06-07T21:08:59.563Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3e/d3ba07a0ab38b5389e10bec4362d21e10a4f667cba2d79ba30837b3a5059/aiohttp-3.14.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9e8f2d660c350b3d0e259c7a7e3d9b7fc8b41210cbcc3d4a7076ff0a5e5c2fdc", size = 1786465, upload-time = "2026-06-07T21:09:01.909Z" }, + { url = "https://files.pythonhosted.org/packages/0b/cb/e2ee978a00cfb2df829704a69528b18154eba5939f45bc1efa8f33aee4c5/aiohttp-3.14.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4691802dda97be727f79d86818acaad7eb8e9252626a1d6b519fedbb92d5e251", size = 1909423, upload-time = "2026-06-07T21:09:04.357Z" }, + { url = "https://files.pythonhosted.org/packages/73/5d/1430334858b1022b58ae50399a918f0bd6fe8fa7fa183598d657ff61e040/aiohttp-3.14.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c389c482a7e9b9dc3ee2701ac46c4125297a3818875b9c305ddb603c04828fd1", size = 2001906, upload-time = "2026-06-07T21:09:06.722Z" }, + { url = "https://files.pythonhosted.org/packages/66/4e/560c7472d3d198a23aa5c8b19a5115bf6a9b77b7d3e4bb363da320430ad2/aiohttp-3.14.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fc0cacab7ba4e56f0f81c82a98c09bed2f39c940107b03a34b168bdf7597edd3", size = 1877095, upload-time = "2026-06-07T21:09:09.011Z" }, + { url = "https://files.pythonhosted.org/packages/0d/f1/4745806578d447db4a784a8591e2dae3afdfc2bcb96f8f81271b13df6543/aiohttp-3.14.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:979ed4717f59b8bb12e3963378fa285d93d367e15bcd66c721311826d3c44a6c", size = 1676222, upload-time = "2026-06-07T21:09:11.461Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c9/48255813cca749a229ef0ab476004ec623728ad79a9c0840616f6c076325/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:38e1e7daaea81df51c952e18483f323d878499a1e2bfe564790e0f9701d6f203", size = 1842922, upload-time = "2026-06-07T21:09:14.118Z" }, + { url = "https://files.pythonhosted.org/packages/3d/c0/bbd054e2bee909f529523a5af3891052606af5143c09f5f183ec3b234676/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:4132e72c608fe9fecb8f409113567605915b83e9bdd3ea56538d2f9cd35002f1", size = 1825035, upload-time = "2026-06-07T21:09:16.447Z" }, + { url = "https://files.pythonhosted.org/packages/a8/ae/90395d4376deceb74e09ec26b6adf7d2015a6f8802d6d84446af860fef04/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:eefd9cc9b6d4a2db5f00a26bc3e4f9acf71926a6ec557cd56c9c6f27c290b665", size = 1849512, upload-time = "2026-06-07T21:09:18.742Z" }, + { url = "https://files.pythonhosted.org/packages/93/bd/fb25f3049957553d4ce0ba6ae480aa2f592a6985497fca590837d16c1be0/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b165790117eea512d7f3fb22f1f6dad3d55a7189571993eb015591c1401276d1", size = 1668571, upload-time = "2026-06-07T21:09:21.458Z" }, + { url = "https://files.pythonhosted.org/packages/3f/22/7f73303d64dd567ff3addca90b556690ed1233a47b8f55d242fb90af3681/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:ed09c7eb1c391271c2ed0314a51903e72a3acb653d5ccfc264cdf3ef11f8269d", size = 1881159, upload-time = "2026-06-07T21:09:23.813Z" }, + { url = "https://files.pythonhosted.org/packages/44/be/0474c5a8b5640e1e4aa1923430a91f4151be82e511373fe764189b89aef5/aiohttp-3.14.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:99abd37084b82f5830c635fddd0b4993b9742a66eb746dacf433c8590e8f9e3c", size = 1841409, upload-time = "2026-06-07T21:09:26.207Z" }, + { url = "https://files.pythonhosted.org/packages/7b/3c/bb4a7cba26956cb3da4553cc2056cf67be5b5ff6e6d8fa4fbdff73bfb7ae/aiohttp-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:47ddf841cdecc810749921d25606dee45857d12d2ad5ddb7b5bd7eab12e4b365", size = 494166, upload-time = "2026-06-07T21:09:28.505Z" }, + { url = "https://files.pythonhosted.org/packages/8a/84/ec80c2c1f66a952555a9f86df6b33af65108a6febfa0471b69013a12f807/aiohttp-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:5e78b522b7a6e27e0b25d19b247b75039ac4c94f99823e3c9e53ae1603a9f7e9", size = 530255, upload-time = "2026-06-07T21:09:30.843Z" }, + { url = "https://files.pythonhosted.org/packages/2a/71/6e22be134a4061ada85a92951b842f2657f17d926b727f3f94c56ae963d6/aiohttp-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:90d53f1609c29ccc2193945ef732428382a28f78d0456ae4d3daf0d48b74f0f6", size = 469640, upload-time = "2026-06-07T21:09:33.028Z" }, ] [package.optional-dependencies] @@ -311,42 +311,42 @@ wheels = [ [[package]] name = "bleach" -version = "6.3.0" +version = "6.4.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "webencodings" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/07/18/3c8523962314be6bf4c8989c79ad9531c825210dd13a8669f6b84336e8bd/bleach-6.3.0.tar.gz", hash = "sha256:6f3b91b1c0a02bb9a78b5a454c92506aa0fdf197e1d5e114d2e00c6f64306d22", size = 203533, upload-time = "2025-10-27T17:57:39.211Z" } +sdist = { url = "https://files.pythonhosted.org/packages/48/3c/e12ac860709702bd5ebeb9b56a4fe334f1001246ee1b8f2b7ee28912df7d/bleach-6.4.0.tar.gz", hash = "sha256:4202482733d85cedd04e59fcb2f89f4e4c7c385a78d3c3c23c30446843a37452", size = 204857, upload-time = "2026-06-05T13:01:13.734Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/3a/577b549de0cc09d95f11087ee63c739bba856cd3952697eec4c4bb91350a/bleach-6.3.0-py3-none-any.whl", hash = "sha256:fe10ec77c93ddf3d13a73b035abaac7a9f5e436513864ccdad516693213c65d6", size = 164437, upload-time = "2025-10-27T17:57:37.538Z" }, + { url = "https://files.pythonhosted.org/packages/58/9d/40b6267367182187139a4000b82a3b287d84d745bccd808e75d916920e9d/bleach-6.4.0-py3-none-any.whl", hash = "sha256:4b6b6a54fff2e69a3dde9d21cc6301220bee3c3cb792187d11403fd795031081", size = 165109, upload-time = "2026-06-05T13:01:12.504Z" }, ] [[package]] name = "boto3" -version = "1.43.21" +version = "1.43.28" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, { name = "s3transfer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/1e/f2/0ef88b6584285002a8a8000e34340f56e82681ad2b8a76ea8bd3ecaa5cb9/boto3-1.43.21.tar.gz", hash = "sha256:6dfeb70bf4f9a3514b91c7199f475f71f939199d62f9c63cd555b033fb283f89", size = 113157, upload-time = "2026-06-03T07:09:23.263Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4e/f2/a976b2a81d8dc7ff675f4b614367a185727061130184a28da0f53f446b97/boto3-1.43.28.tar.gz", hash = "sha256:8391fdcc4d8e1d4e0bf96575a7e5610964a4d401dafa4dccb0a5bade8dd3fbb0", size = 113202, upload-time = "2026-06-11T19:29:01.464Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/ea/5352950cbee9d1e8392e5396ddbc6defc982414e2abc004b501139bce13c/boto3-1.43.21-py3-none-any.whl", hash = "sha256:8bb863b32dabe5baa4f2e3701778c259243ba117e4811a595411819958c4fb1b", size = 140534, upload-time = "2026-06-03T07:09:21.18Z" }, + { url = "https://files.pythonhosted.org/packages/c3/a5/47db150ea6380f11569b87d3ad064e3c929e5abe227a549d472fab6f5f3a/boto3-1.43.28-py3-none-any.whl", hash = "sha256:4fe6df2163aea02b561eca0d685e2f41a059d71f03721a3e79c3b522e79a3b56", size = 140536, upload-time = "2026-06-11T19:29:00.143Z" }, ] [[package]] name = "botocore" -version = "1.43.21" +version = "1.43.28" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/97/d9d26cebf0a8533105e183d8438931c0b196e52484cd5bf00e8443ac1b2d/botocore-1.43.21.tar.gz", hash = "sha256:17604607efe28894e947401379e569cc8f0fe2d69337ece98bd0c82d1bcfaf92", size = 15451979, upload-time = "2026-06-03T07:09:11.489Z" } +sdist = { url = "https://files.pythonhosted.org/packages/02/dc/1b01808003f88f8a328732c979f20cb0456791048b4440fc4abcae08c1a0/botocore-1.43.28.tar.gz", hash = "sha256:9bbad501a68e4ffdbeff76a382507f5d7827abc316f34a218ab76f5293e6c78d", size = 15503514, upload-time = "2026-06-11T19:28:50.989Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bb/c7/8c60049357e96d663980d66b98a44cb3626a7e5eaca66480b97826eb5379/botocore-1.43.21-py3-none-any.whl", hash = "sha256:f021ba3e844c36031106fc531ec90259ef005ba5d04f691df53bc4ecbd08f0dd", size = 15135303, upload-time = "2026-06-03T07:09:06.115Z" }, + { url = "https://files.pythonhosted.org/packages/fa/8c/14916c353ce8a29d14cf6308c2bef842bbb25dde6defc620e26e28063331/botocore-1.43.28-py3-none-any.whl", hash = "sha256:8147adea89b4c9324e842cd8c01ea1a0e17c92cb6ebeaa8cb774f821cb5a7629", size = 15188401, upload-time = "2026-06-11T19:28:47.244Z" }, ] [[package]] @@ -573,55 +573,55 @@ wheels = [ [[package]] name = "cryptography" -version = "48.0.0" +version = "48.0.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/9f/a9/db8f313fdcd85d767d4973515e1db101f9c71f95fced83233de224673757/cryptography-48.0.0.tar.gz", hash = "sha256:5c3932f4436d1cccb036cb0eaef46e6e2db91035166f1ad6505c3c9d5a635920", size = 832984, upload-time = "2026-05-04T22:59:38.133Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/3d/01f6dd9190170a5a241e0e98c2d04be3664a9e6f5b9b872cde63aff1c3dd/cryptography-48.0.0-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:0c558d2cdffd8f4bbb30fc7134c74d2ca9a476f830bb053074498fbc86f41ed6", size = 8001587, upload-time = "2026-05-04T22:57:36.803Z" }, - { url = "https://files.pythonhosted.org/packages/b2/6e/e90527eef33f309beb811cf7c982c3aeffcce8e3edb178baa4ca3ae4a6fa/cryptography-48.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f5333311663ea94f75dd408665686aaf426563556bb5283554a3539177e03b8c", size = 4690433, upload-time = "2026-05-04T22:57:40.373Z" }, - { url = "https://files.pythonhosted.org/packages/90/04/673510ed51ddff56575f306cf1617d80411ee76831ccd3097599140efdfe/cryptography-48.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7995ef305d7165c3f11ae07f2517e5a4f1d5c18da1376a0a9ed496336b69e5f3", size = 4710620, upload-time = "2026-05-04T22:57:42.935Z" }, - { url = "https://files.pythonhosted.org/packages/14/d5/e9c4ef932c8d800490c34d8bd589d64a31d5890e27ec9e9ad532be893294/cryptography-48.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:40ba1f85eaa6959837b1d51c9767e230e14612eea4ef110ee8854ada22da1bf5", size = 4696283, upload-time = "2026-05-04T22:57:45.294Z" }, - { url = "https://files.pythonhosted.org/packages/0c/29/174b9dfb60b12d59ecfc6cfa04bc88c21b42a54f01b8aae09bb6e51e4c7f/cryptography-48.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:369a6348999f94bbd53435c894377b20ab95f25a9065c283570e70150d8abc3c", size = 5296573, upload-time = "2026-05-04T22:57:47.933Z" }, - { url = "https://files.pythonhosted.org/packages/95/38/0d29a6fd7d0d1373f0c0c88a04ba20e359b257753ac497564cd660fc1d55/cryptography-48.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a0e692c683f4df67815a2d258b324e66f4738bd7a96a218c826dce4f4bd05d8f", size = 4743677, upload-time = "2026-05-04T22:57:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/30/be/eef653013d5c63b6a490529e0316f9ac14a37602965d4903efed1399f32b/cryptography-48.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:18349bbc56f4743c8b12dc32e2bccb2cf83ee8b69a3bba74ef8ae857e26b3d25", size = 4330808, upload-time = "2026-05-04T22:57:52.301Z" }, - { url = "https://files.pythonhosted.org/packages/84/9e/500463e87abb7a0a0f9f256ec21123ecde0a7b5541a15e840ea54551fd81/cryptography-48.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:7e8eac43dfca5c4cccc6dad9a80504436fca53bb9bc3100a2386d730fbe6b602", size = 4695941, upload-time = "2026-05-04T22:57:54.603Z" }, - { url = "https://files.pythonhosted.org/packages/e3/dc/7303087450c2ec9e7fbb750e17c2abfbc658f23cbd0e54009509b7cc4091/cryptography-48.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9ccdac7d40688ecb5a3b4a604b8a88c8002e3442d6c60aead1db2a89a041560c", size = 5252579, upload-time = "2026-05-04T22:57:57.207Z" }, - { url = "https://files.pythonhosted.org/packages/d0/c0/7101d3b7215edcdc90c45da544961fd8ed2d6448f77577460fa75a8443f7/cryptography-48.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:bd72e68b06bb1e96913f97dd4901119bc17f39d4586a5adf2d3e47bc2b9d58b5", size = 4743326, upload-time = "2026-05-04T22:57:59.535Z" }, - { url = "https://files.pythonhosted.org/packages/ac/d8/5b833bad13016f562ab9d063d68199a4bd121d18458e439515601d3357ec/cryptography-48.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:59baa2cb386c4f0b9905bd6eb4c2a79a69a128408fd31d32ca4d7102d4156321", size = 4826672, upload-time = "2026-05-04T22:58:01.996Z" }, - { url = "https://files.pythonhosted.org/packages/98/e1/7074eb8bf3c135558c73fc2bcf0f5633f912e6fb87e868a55c454080ef09/cryptography-48.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9249e3cd978541d665967ac2cb2787fd6a62bddf1e75b3e347a594d7dacf4f74", size = 4972574, upload-time = "2026-05-04T22:58:03.968Z" }, - { url = "https://files.pythonhosted.org/packages/04/70/e5a1b41d325f797f39427aa44ef8baf0be500065ab6d8e10369d850d4a4f/cryptography-48.0.0-cp311-abi3-win32.whl", hash = "sha256:9c459db21422be75e2809370b829a87eb37f74cd785fc4aa9ea1e5f43b47cda4", size = 3294868, upload-time = "2026-05-04T22:58:06.467Z" }, - { url = "https://files.pythonhosted.org/packages/f4/ac/8ac51b4a5fc5932eb7ee5c517ba7dc8cd834f0048962b6b352f00f41ebf9/cryptography-48.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:5b012212e08b8dd5edc78ef54da83dd9892fd9105323b3993eff6bea65dc21d7", size = 3817107, upload-time = "2026-05-04T22:58:08.845Z" }, - { url = "https://files.pythonhosted.org/packages/6b/84/70e3feea9feea87fd7cbe77efb2712ae1e3e6edf10749dc6e95f4e60e455/cryptography-48.0.0-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:3cb07a3ed6431663cd321ea8a000a1314c74211f823e4177fefa2255e057d1ec", size = 7986556, upload-time = "2026-05-04T22:58:11.172Z" }, - { url = "https://files.pythonhosted.org/packages/89/6e/18e07a618bb5442ba10cf4df16e99c071365528aa570dfcb8c02e25a303b/cryptography-48.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8c7378637d7d88016fa6791c159f698b3d3eed28ebf844ac36b9dc04a14dae18", size = 4684776, upload-time = "2026-05-04T22:58:13.712Z" }, - { url = "https://files.pythonhosted.org/packages/be/6a/4ea3b4c6c6759794d5ee2103c304a5076dc4b19ae1f9fe47dba439e159e9/cryptography-48.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:cc90c0b39b2e3c65ef52c804b72e3c58f8a04ab2a1871272798e5f9572c17d20", size = 4698121, upload-time = "2026-05-04T22:58:16.448Z" }, - { url = "https://files.pythonhosted.org/packages/2f/59/6ff6ad6cae03bb887da2a5860b2c9805f8dac969ef01ce563336c49bd1d1/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:76341972e1eff8b4bea859f09c0d3e64b96ce931b084f9b9b7db8ef364c30eff", size = 4690042, upload-time = "2026-05-04T22:58:18.544Z" }, - { url = "https://files.pythonhosted.org/packages/ca/b4/fc334ed8cfd705aca282fe4d8f5ae64a8e0f74932e9feecb344610cf6e4d/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:55b7718303bf06a5753dcdccf2f3945cf18ad7bffde41b61226e4db31ab89a9c", size = 5282526, upload-time = "2026-05-04T22:58:20.75Z" }, - { url = "https://files.pythonhosted.org/packages/11/08/9f8c5386cc4cd90d8255c7cdd0f5baf459a08502a09de30dc51f553d38dc/cryptography-48.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:a64697c641c7b1b2178e573cbc31c7c6684cd56883a478d75143dbb7118036db", size = 4733116, upload-time = "2026-05-04T22:58:23.627Z" }, - { url = "https://files.pythonhosted.org/packages/b8/77/99307d7574045699f8805aa500fa0fb83422d115b5400a064ddd306d7750/cryptography-48.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:561215ea3879cb1cbbf272867e2efda62476f240fb58c64de6b393ae19246741", size = 4316030, upload-time = "2026-05-04T22:58:25.581Z" }, - { url = "https://files.pythonhosted.org/packages/fd/36/a608b98337af3cb2aff4818e406649d30572b7031918b04c87d979495348/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ad64688338ed4bc1a6618076ba75fd7194a5f1797ac60b47afe926285adb3166", size = 4689640, upload-time = "2026-05-04T22:58:27.747Z" }, - { url = "https://files.pythonhosted.org/packages/dd/a6/825010a291b4438aecc1f568bc428189fc1175515223632477c07dc0a6df/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:906cbf0670286c6e0044156bc7d4af9cbb0ef6db9f73e52c3ec56ba6bdde5336", size = 5237657, upload-time = "2026-05-04T22:58:29.848Z" }, - { url = "https://files.pythonhosted.org/packages/b9/09/4e76a09b4caa29aad535ddc806f5d4c5d01885bd978bd984fbc6ca032cae/cryptography-48.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:ea8990436d914540a40ab24b6a77c0969695ed52f4a4874c5137ccf7045a7057", size = 4732362, upload-time = "2026-05-04T22:58:32.009Z" }, - { url = "https://files.pythonhosted.org/packages/18/78/444fa04a77d0cb95f417dda20d450e13c56ba8e5220fc892a1658f44f882/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c18684a7f0cc9a3cb60328f496b8e3372def7c5d2df39ac267878b05565aaaae", size = 4819580, upload-time = "2026-05-04T22:58:34.254Z" }, - { url = "https://files.pythonhosted.org/packages/38/85/ea67067c70a1fd4be2c63d35eeed82658023021affccc7b17705f8527dd2/cryptography-48.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:9be5aafa5736574f8f15f262adc81b2a9869e2cfe9014d52a44633905b40d52c", size = 4963283, upload-time = "2026-05-04T22:58:36.376Z" }, - { url = "https://files.pythonhosted.org/packages/75/54/cc6d0f3deac3e81c7f847e8a189a12b6cdd65059b43dad25d4316abd849a/cryptography-48.0.0-cp314-cp314t-win32.whl", hash = "sha256:c17dfe85494deaeddc5ce251aebd1d60bbe6afc8b62071bb0b469431a000124f", size = 3270954, upload-time = "2026-05-04T22:58:38.791Z" }, - { url = "https://files.pythonhosted.org/packages/49/67/cc947e288c0758a4e5473d1dcb743037ab7785541265a969240b8885441a/cryptography-48.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27241b1dc9962e056062a8eef1991d02c3a24569c95975bd2322a8a52c6e5e12", size = 3797313, upload-time = "2026-05-04T22:58:40.746Z" }, - { url = "https://files.pythonhosted.org/packages/f2/63/61d4a4e1c6b6bab6ce1e213cd36a24c415d90e76d78c5eb8577c5541d2e8/cryptography-48.0.0-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:58d00498e8933e4a194f3076aee1b4a97dfec1a6da444535755822fe5d8b0b86", size = 7983482, upload-time = "2026-05-04T22:58:43.769Z" }, - { url = "https://files.pythonhosted.org/packages/d5/ac/f5b5995b87770c693e2596559ffafe195b4033a57f14a82268a2842953f3/cryptography-48.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:614d0949f4790582d2cc25553abd09dd723025f0c0e7c67376a1d77196743d6e", size = 4683266, upload-time = "2026-05-04T22:58:46.064Z" }, - { url = "https://files.pythonhosted.org/packages/ec/c6/8b14f67e18338fbc4adb76f66c001f5c3610b3e2d1837f268f47a347dbbb/cryptography-48.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7ce4bfae76319a532a2dc68f82cc32f5676ee792a983187dac07183690e5c66f", size = 4696228, upload-time = "2026-05-04T22:58:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/ea/73/f808fbae9514bd91b47875b003f13e284c8c6bdfd904b7944e803937eec1/cryptography-48.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:2eb992bbd4661238c5a397594c83f5b4dc2bc5b848c365c8f991b6780efcc5c7", size = 4689097, upload-time = "2026-05-04T22:58:50.9Z" }, - { url = "https://files.pythonhosted.org/packages/93/01/d86632d7d28db8ae83221995752eeb6639ffb374c2d22955648cf8d52797/cryptography-48.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:22a5cb272895dce158b2cacdfdc3debd299019659f42947dbdac6f32d68fe832", size = 5283582, upload-time = "2026-05-04T22:58:53.017Z" }, - { url = "https://files.pythonhosted.org/packages/02/e1/50edc7a50334807cc4791fc4a0ce7468b4a1416d9138eab358bfc9a3d70b/cryptography-48.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2b4d59804e8408e2fea7d1fbaf218e5ec984325221db76e6a241a9abd6cdd95c", size = 4730479, upload-time = "2026-05-04T22:58:55.611Z" }, - { url = "https://files.pythonhosted.org/packages/6f/af/99a582b1b1641ff5911ac559beb45097cf79efd4ead4657f578ef1af2d47/cryptography-48.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:984a20b0f62a26f48a3396c72e4bc34c66e356d356bf370053066b3b6d54634a", size = 4326481, upload-time = "2026-05-04T22:58:57.607Z" }, - { url = "https://files.pythonhosted.org/packages/90/ee/89aa26a06ef0a7d7611788ffd571a7c50e368cc6a4d5eef8b4884e866edb/cryptography-48.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5a5ed8fde7a1d09376ca0b40e68cd59c69fe23b1f9768bd5824f54681626032a", size = 4688713, upload-time = "2026-05-04T22:59:00.077Z" }, - { url = "https://files.pythonhosted.org/packages/70/ba/bcb1b0bb7a33d4c7c0c4d4c7874b4a62ae4f56113a5f4baefa362dfb1f0f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:8cd666227ef7af430aa5914a9910e0ddd703e75f039cef0825cd0da71b6b711a", size = 5238165, upload-time = "2026-05-04T22:59:02.317Z" }, - { url = "https://files.pythonhosted.org/packages/c9/70/ca4003b1ce5ca3dc3186ada51908c8a9b9ff7d5cab83cc0d43ee14ec144f/cryptography-48.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:9071196d81abc88b3516ac8cdfad32e2b66dd4a5393a8e68a961e9161ddc6239", size = 4729947, upload-time = "2026-05-04T22:59:05.255Z" }, - { url = "https://files.pythonhosted.org/packages/44/a0/4ec7cf774207905aef1a8d11c3750d5a1db805eb380ee4e16df317870128/cryptography-48.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1e2d54c8be6152856a36f0882ab231e70f8ec7f14e93cf87db8a2ed056bf160c", size = 4822059, upload-time = "2026-05-04T22:59:07.802Z" }, - { url = "https://files.pythonhosted.org/packages/1e/75/a2e55f99c16fcac7b5d6c1eb19ad8e00799854d6be5ca845f9259eae1681/cryptography-48.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a5da777e32ffed6f85a7b2b3f7c5cbc88c146bfcd0a1d7baf5fcc6c52ee35dd4", size = 4960575, upload-time = "2026-05-04T22:59:09.851Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/6e6f32143ab5d8b36ca848a502c4bcd477ae75b9e1677e3530d669062578/cryptography-48.0.0-cp39-abi3-win32.whl", hash = "sha256:77a2ccbbe917f6710e05ba9adaa25fb5075620bf3ea6fb751997875aff4ae4bd", size = 3279117, upload-time = "2026-05-04T22:59:12.019Z" }, - { url = "https://files.pythonhosted.org/packages/9d/9a/0fea98a70cf1749d41d738836f6349d97945f7c89433a259a6c2642eefeb/cryptography-48.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:16cd65b9330583e4619939b3a3843eec1e6e789744bb01e7c7e2e62e33c239c8", size = 3792100, upload-time = "2026-05-04T22:59:14.884Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" }, + { url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" }, + { url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" }, + { url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" }, + { url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" }, + { url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" }, + { url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" }, + { url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" }, + { url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" }, + { url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" }, + { url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" }, + { url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" }, + { url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" }, + { url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" }, + { url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" }, + { url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" }, + { url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" }, + { url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" }, + { url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" }, + { url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" }, + { url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" }, + { url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" }, + { url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" }, + { url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" }, + { url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" }, + { url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" }, + { url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" }, + { url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" }, + { url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" }, + { url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" }, + { url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" }, + { url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" }, + { url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" }, + { url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" }, + { url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" }, + { url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" }, ] [[package]] @@ -648,11 +648,11 @@ wheels = [ [[package]] name = "distlib" -version = "0.4.1" +version = "0.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/86/b2/d6fc3f2347f43dada79e5ff118493e8109c98400a0e29a1d5264a3aa479b/distlib-0.4.1.tar.gz", hash = "sha256:c3804d0d2d4b5fcd44036eb860cb6660485fcdf5c2aba53dc324d805837ea65b", size = 610526, upload-time = "2026-06-02T11:17:40.691Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/02/bd72be9134d25ed783ecbbc38a539ffaefbf90c78418c7fb7229600dbac7/distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed", size = 615141, upload-time = "2026-06-12T08:04:52.847Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/25/18/3497c4fa83a76dcb154923fd2075522e8dd6995ecee4093c00ae18160046/distlib-0.4.1-py2.py3-none-any.whl", hash = "sha256:9c2c552c68cbadc619f2d0ed3a69e27c351a3f4c9baa9ffb7df9e9cdc3d19a97", size = 469216, upload-time = "2026-06-02T11:17:38.779Z" }, + { url = "https://files.pythonhosted.org/packages/02/08/9c41fb51ab5b43eb21674aff13df270e8ba6c4b29c8624e328dc7a9482af/distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b", size = 470628, upload-time = "2026-06-12T08:04:50.506Z" }, ] [[package]] @@ -918,11 +918,11 @@ standard-no-fastapi-cloud-cli = [ [[package]] name = "filelock" -version = "3.29.0" +version = "3.29.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/fe/997687a931ab51049acce6fa1f23e8f01216374ea81374ddee763c493db5/filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90", size = 57571, upload-time = "2026-04-19T15:39:10.068Z" } +sdist = { url = "https://files.pythonhosted.org/packages/91/f5/3557bf28e0f1943e4849154c821533706e6dea010f96fb6aa0b6949037d1/filelock-3.29.3.tar.gz", hash = "sha256:7fc1b3f39cf172fd8203812043c57b8a65aef9969f38b6704f628b881f761a84", size = 61956, upload-time = "2026-06-10T17:37:11.832Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/47/dd9a212ef6e343a6857485ffe25bba537304f1913bdbed446a23f7f592e1/filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258", size = 39812, upload-time = "2026-04-19T15:39:08.752Z" }, + { url = "https://files.pythonhosted.org/packages/81/8f/b61d427c4f49a8bdadc93f4e7e74df8a6df6f77ee6e26bf0df53d3925363/filelock-3.29.3-py3-none-any.whl", hash = "sha256:e58333029cc9b925f39aad59b1d8f0a1ad836af4e60d7217f4a4dba87461261d", size = 42324, upload-time = "2026-06-10T17:37:10.37Z" }, ] [[package]] @@ -1059,11 +1059,11 @@ wheels = [ [[package]] name = "graphql-core" -version = "3.2.8" +version = "3.2.11" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/68/c5/36aa96205c3ecbb3d34c7c24189e4553c7ca2ebc7e1dd07432339b980272/graphql_core-3.2.8.tar.gz", hash = "sha256:015457da5d996c924ddf57a43f4e959b0b94fb695b85ed4c29446e508ed65cf3", size = 513181, upload-time = "2026-03-05T19:55:37.332Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4d/90/f2aff026ab4aebd80eb71905106a0885f4cfde85dcf965543f45bed0d9ee/graphql_core-3.2.11.tar.gz", hash = "sha256:e7e156d10beb127cab5c89ff0da71416fc73d27c484a4757d3b2d35633774802", size = 528407, upload-time = "2026-06-05T13:45:22.915Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl", hash = "sha256:cbee07bee1b3ed5e531723685369039f32ff815ef60166686e0162f540f1520c", size = 207349, upload-time = "2026-03-05T19:55:35.911Z" }, + { url = "https://files.pythonhosted.org/packages/00/15/b92b4e1d88d02c6eff9733c9eea21846ab435cc4d813d84ccc5d335955df/graphql_core-3.2.11-py3-none-any.whl", hash = "sha256:0b3e35ff41e9adba53021ab0cef475eb18f57c7f53f0f2ca55567fbf3c537ea0", size = 214879, upload-time = "2026-06-05T13:45:21.245Z" }, ] [[package]] @@ -1216,7 +1216,7 @@ wheels = [ [[package]] name = "ipython" -version = "9.14.0" +version = "9.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, @@ -1231,9 +1231,9 @@ dependencies = [ { name = "stack-data" }, { name = "traitlets" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/21/c2/c0064cf15d026501a1ef70e42efd9c3f818663089399aacc5e37a82901c1/ipython-9.14.0.tar.gz", hash = "sha256:6f27ff0f1d9ea050e0551f71568bc4b34d8aba579e8f111c5b4175f44ac6b4aa", size = 4432601, upload-time = "2026-05-29T15:13:24.611Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/23/3a27530575643c8bb7bfc757a28e2e7ef80092afbf59a2bc5716320b6602/ipython-9.14.1.tar.gz", hash = "sha256:f913bf74df06d458e46ced84ca506c23797590d594b236fe60b14df213291e7b", size = 4433457, upload-time = "2026-06-05T08:12:34.921Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/14/a3/9e59340f02c1dc8f8c0a05b09244712b8609eb5439f9996e887e2b82f452/ipython-9.14.0-py3-none-any.whl", hash = "sha256:8fd984a3372c14b12790b084ba6b5cff5678c0cb063244a0034f06a51f20d6c2", size = 627457, upload-time = "2026-05-29T15:13:22.942Z" }, + { url = "https://files.pythonhosted.org/packages/9d/22/58818a63eaf8982b67632b1bc20585c811611b15a8da19d6012323dc76a5/ipython-9.14.1-py3-none-any.whl", hash = "sha256:5d4a9ecaa3b10e6e5f269dd0948bdb58ca9cb851899cd23e07c320d3eb11613c", size = 627770, upload-time = "2026-06-05T08:12:33.045Z" }, ] [[package]] @@ -1704,11 +1704,11 @@ wheels = [ [[package]] name = "phonenumberslite" -version = "9.0.31" +version = "9.0.32" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/11/87590d775cd3e4586609e5ad06a3ac023dbcd2d8873d70df2e756d3a33e7/phonenumberslite-9.0.31.tar.gz", hash = "sha256:580d23864b4d5cd75a3967a9a2a1965a5f85d7d092ed05e40d547b995eafd8c2", size = 288685, upload-time = "2026-05-23T06:08:48.278Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/72/840fb0a587ddbc2aff23e9415ca9d86394aa13343a3d9ea4db185f749796/phonenumberslite-9.0.32.tar.gz", hash = "sha256:d1bbdbc81356f98737cd0e342c84f9abb325b7342c70cad3519c7e2cd478f8c5", size = 288616, upload-time = "2026-06-05T05:48:22.319Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3e/cd/561a41cd1eb4269e884bf09adc3728be3f4ae2773ad0154ce64ff2dddb35/phonenumberslite-9.0.31-py2.py3-none-any.whl", hash = "sha256:dbbb5e4c5c561ffc7f67af808aa391eb1a10b777645aac08ba4a1479fb172216", size = 473266, upload-time = "2026-05-23T06:08:46.693Z" }, + { url = "https://files.pythonhosted.org/packages/9c/0d/c7ab9feff3cb55e9743e8b56b05dd23564dfc4b0c1e395f396e384f39db0/phonenumberslite-9.0.32-py2.py3-none-any.whl", hash = "sha256:e129943437cb1f7b0b7dc9d3aee482fae04871a47604064fb4c912c97ae53826", size = 473221, upload-time = "2026-06-05T05:48:20.557Z" }, ] [[package]] @@ -2200,15 +2200,15 @@ wheels = [ [[package]] name = "python-discovery" -version = "1.4.0" +version = "1.4.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "platformdirs" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/12/38c1a0b1e64806780c9563e3fc9f6e472251839662587cfbe9bfaf2ae10a/python_discovery-1.4.0.tar.gz", hash = "sha256:eb8bc7daad3c226c147e45bb4e970a1feb1bf4048ee178e6db59e197b8010ce3", size = 68455, upload-time = "2026-05-28T01:15:37.639Z" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/1a/cbbaf13b730abb0a16b964d984e19f2fe520c21a4dc664051359a3f5a9e7/python_discovery-1.4.2.tar.gz", hash = "sha256:8f3746c4b4968d22afbb97d36e1a0e5b66e6c0f297290f2e95f05b9b8bf18690", size = 70277, upload-time = "2026-06-11T16:10:42.383Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/8d/3d316429f65029532bb1e28ff77b797d86b5ac3915bb44ca4e19aa283d43/python_discovery-1.4.0-py3-none-any.whl", hash = "sha256:26ed78d703e234879a66244c7d4114563fb13ec5cd30a2d1357e5fb4850782da", size = 33217, upload-time = "2026-05-28T01:15:36.573Z" }, + { url = "https://files.pythonhosted.org/packages/1a/82/a70006589557f267f15bd384c0642ad49f0d97b690c3a05b166b9dcbad3b/python_discovery-1.4.2-py3-none-any.whl", hash = "sha256:475803f53b7b2ed6e490e27373f9d8340f7d2eebf9acdaf645d7d714c97bb500", size = 33886, upload-time = "2026-06-11T16:10:41.192Z" }, ] [[package]] @@ -2231,11 +2231,11 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.30" +version = "0.0.32" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4b/82/c8cd43a6e0719bf5a3b034f6726dd701f75829c08944c83d4b95d02ed0e8/python_multipart-0.0.30.tar.gz", hash = "sha256:0edfe0475c1f46ddd3ff7785a626f6118af32bdcf359bb21260367313bb32118", size = 46316, upload-time = "2026-05-31T19:24:55.198Z" } +sdist = { url = "https://files.pythonhosted.org/packages/5b/42/55c32bb9b12693c092ad250a0e82edb5b31ddeda6eb772de5f308b3804ad/python_multipart-0.0.32.tar.gz", hash = "sha256:be54b7f3fa167bb83e4fcd936b887b708f4e57fe75911c02aebf53efaf8d938e", size = 46881, upload-time = "2026-06-04T16:18:58.647Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/fd/0318007beb234790993d3ec5afd051d1dbceb733e81e3afe2b981ece3f37/python_multipart-0.0.30-py3-none-any.whl", hash = "sha256:830964def8c90607ac5daa00514e3987815865713ade8d20febc9177ac0c3c5b", size = 29730, upload-time = "2026-05-31T19:24:53.814Z" }, + { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, ] [[package]] @@ -2400,16 +2400,16 @@ wheels = [ [[package]] name = "rich-toolkit" -version = "0.20.0" +version = "0.20.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "rich" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c3/49/d7a4fd4f39c195b73f78694af3e812943a4181a8d48a11035425d0f6d71f/rich_toolkit-0.20.0.tar.gz", hash = "sha256:bb05382554d4f46865dfca2fccccf30768ef37e0347207d00f034d9b36b25021", size = 203144, upload-time = "2026-06-02T21:11:38.48Z" } +sdist = { url = "https://files.pythonhosted.org/packages/29/63/3e427c62f1992945c997d4ec31e2fcb37d26aadbe5aa44ae5b29f7f64d26/rich_toolkit-0.20.1.tar.gz", hash = "sha256:c7336ae281f435c785acecaedc4b71d4b663dc73d9c8079fea96372527e822a4", size = 203473, upload-time = "2026-06-05T08:56:57.679Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/67/b5/6b6efd9e305653fae68ed0b712bc659cd3c5541ec54416e6bb14af52acca/rich_toolkit-0.20.0-py3-none-any.whl", hash = "sha256:906e5b8741fafc46159c5f719fd30fd3c9dd8f2c31b8161dc8c612f98b8da01a", size = 35379, upload-time = "2026-06-02T21:11:37.564Z" }, + { url = "https://files.pythonhosted.org/packages/00/88/309f07d08155da2ba1d5ceb42d270fb42fbe34a807684543e3ffc10fe713/rich_toolkit-0.20.1-py3-none-any.whl", hash = "sha256:2a6d5f8e15759b9eba5a9ee63da10b275359ead20e5a0fc92bd5b4dbae8ce4bf", size = 35525, upload-time = "2026-06-05T08:56:58.586Z" }, ] [[package]] @@ -2480,27 +2480,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.15.15" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/84/6f/a76f7d96e5c962f5b69cee865e49c15c1116897c01990faa8a57edb62e7f/ruff-0.15.15.tar.gz", hash = "sha256:b8dff018130b46d8e5bf0f926ef6b60cf871d6d5ae45fc9334e09632daa741d6", size = 4706985, upload-time = "2026-05-28T14:16:57.784Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fa/9d/3a45c05b8ab04b4705989de70a79008e27c8003296a0feaee9edc18dd7e9/ruff-0.15.15-py3-none-linux_armv6l.whl", hash = "sha256:cf93e5388f412e1b108b1f8b34a6e036b70fe8aff89393befad96fe48670311b", size = 10710652, upload-time = "2026-05-28T14:16:06.701Z" }, - { url = "https://files.pythonhosted.org/packages/05/66/da974431624bf3b49f6ee1f9543c02d929ff1cba78b0d5a79c38cf21f744/ruff-0.15.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ac5a646d1f6a7dadd5d50842dae2c1f9862ac887ef5d1b1375e02def791fde6e", size = 11096615, upload-time = "2026-05-28T14:16:23.313Z" }, - { url = "https://files.pythonhosted.org/packages/8c/09/7443452e5d290230a712103f2fdceeef7184f3ec99a2bd01c8be78aaceb5/ruff-0.15.15-py3-none-macosx_11_0_arm64.whl", hash = "sha256:77d955a431430c66f72dd94e379ad38a16daea3d25094872ac4edf9e797be530", size = 10436683, upload-time = "2026-05-28T14:16:40.974Z" }, - { url = "https://files.pythonhosted.org/packages/53/01/d330c26a57fa4f3943a14424904027428315b700fe4d14a84bb123a649e5/ruff-0.15.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7614ee79c69788cf6cedd568069ade9cecc22a1ad20494efe8d0c9ebb4b622d4", size = 10769064, upload-time = "2026-05-28T14:16:28.905Z" }, - { url = "https://files.pythonhosted.org/packages/1d/85/cc8770f8bdff541b1da8392d1634141fe4a0e3f4ee596605959b7906c27f/ruff-0.15.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3cdb1679e06a1f6b47bc384714ae96f6e2fb65ca441eb78c43d2ca554176ce1f", size = 10511987, upload-time = "2026-05-28T14:16:43.732Z" }, - { url = "https://files.pythonhosted.org/packages/7c/29/8c190c1472b63013583ba391f3342036e02010544c1270455ed8e519bdf3/ruff-0.15.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2728b93d7b23a603ea2c0ac6eb73d760bd38ec9de35f35fb41e18f7a3fee7622", size = 11275100, upload-time = "2026-05-28T14:16:55.244Z" }, - { url = "https://files.pythonhosted.org/packages/9f/6b/7e145ce2cc8e63d6834eca03d83a0e18d121def5c69f91b4cf4011ed4879/ruff-0.15.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be582fcc0db438902c7792b08d6ddf6c9b9e21addaa10092c2c741cfb09e5a45", size = 12176903, upload-time = "2026-05-28T14:16:14.368Z" }, - { url = "https://files.pythonhosted.org/packages/80/a3/d5974637f68e451f7fadf015cf3101d1cd7d8ba5027cffe0b9e3826ebe6b/ruff-0.15.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7aa77465b8ecaf1a27bea098d696f7fed5e1eccbd10b321b682d6de586ae5627", size = 11404550, upload-time = "2026-05-28T14:16:20.138Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1c/e6e5e568f22be4fb05d6244234aba384c06b451252453b821e1a529263cf/ruff-0.15.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48decfa11d740de4889de623be1463308346312f2409a56e24aa280c86162dc4", size = 11382027, upload-time = "2026-05-28T14:16:46.615Z" }, - { url = "https://files.pythonhosted.org/packages/1d/01/170921b49fcd2e8858825593f91cf7146c3e40a5c3e6df763e4bb0484dde/ruff-0.15.15-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:a5015088452ca0081387063649ec67f06d3d1d6b8b936a1f836b5e9657ecd48c", size = 11366041, upload-time = "2026-05-28T14:16:26.247Z" }, - { url = "https://files.pythonhosted.org/packages/87/54/a7bad711d7de93254e15e06a4c375b89a03d18de45d3e5dcc86a4472fb1a/ruff-0.15.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f5294aab6356c81600fcdea3a62bb1b924dfd5e91767c12318d3f68f86af57cd", size = 10741795, upload-time = "2026-05-28T14:16:17.11Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/38c075963668f8b41c6914ee0f6f318727fbe30ab9145cb29e6df464c5fa/ruff-0.15.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:db5bd4d802415cca656dc1616070b725952d6ae95eb5d4831e49fbd94a38f75f", size = 10511117, upload-time = "2026-05-28T14:16:31.767Z" }, - { url = "https://files.pythonhosted.org/packages/9d/96/6ff689e1f7e375d1d97075eca022f74c2bab59554a432fe4d2e6f091986a/ruff-0.15.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:587a6278ed42059191c1a466e490bd7930fb50bd2e255398bc29616c895a61cb", size = 10994867, upload-time = "2026-05-28T14:16:35.149Z" }, - { url = "https://files.pythonhosted.org/packages/c3/c2/5dce0ab9f92a8d534fa62b9bf9caca3eddb8c1a81b616f5e195ada4f0d6e/ruff-0.15.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:df0c1c084f5f4be9812f61518a45c440d3c30d69ce4bf6c5270e66d38338f02a", size = 11482101, upload-time = "2026-05-28T14:16:49.598Z" }, - { url = "https://files.pythonhosted.org/packages/b1/c0/1003b60edd697c649faf61f1a34094b1abb38fb3d1181e3f895781250a08/ruff-0.15.15-py3-none-win32.whl", hash = "sha256:29428ea79694afbe756d45fd59b36f22b6b020dc0443cf7de0173046236964b9", size = 10716774, upload-time = "2026-05-28T14:16:52.337Z" }, - { url = "https://files.pythonhosted.org/packages/02/a8/1269eddd6945a06c23f055ef7848886e37cf9d6a8bebb386a3115f01470c/ruff-0.15.15-py3-none-win_amd64.whl", hash = "sha256:8df0323902e15e24bc4bf246da830573d3cf3352bd0b9a164eab335d111ff4a4", size = 11868463, upload-time = "2026-05-28T14:16:11.333Z" }, - { url = "https://files.pythonhosted.org/packages/4e/b2/920464c907b191e37469d477a1aa8bc048b8f36c4c1610dfa4ab87b39e18/ruff-0.15.15-py3-none-win_arm64.whl", hash = "sha256:3c8ceca6792f38196b8f589bc92eccd03eef286602da92e5dc05cc42ef6441b7", size = 11138498, upload-time = "2026-05-28T14:16:38.425Z" }, +version = "0.15.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/a9/3abdf488f1bf3d24c699415e454ed554a6350d5d89ce183be1ee0a3361ac/ruff-0.15.17.tar.gz", hash = "sha256:2ec446937fd16c8c4de2674a209cc5af64d9c6f17d21fbf1151054fa0bcf5219", size = 4743346, upload-time = "2026-06-11T17:54:47.663Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/4d/e11259f5da07cb6afb2d074c31bf09da9671993f7329d4f15d2fdc458301/ruff-0.15.17-py3-none-linux_armv6l.whl", hash = "sha256:d9feddb927fc68bd295f5eebc587a7e42cfaf9b65f60ca4a2386febff575da8f", size = 10856677, upload-time = "2026-06-11T17:54:49.533Z" }, + { url = "https://files.pythonhosted.org/packages/29/3e/772d679e1a0dc058e58875bd2c0cb713a0530877b4a76fee3c7966df0d49/ruff-0.15.17-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:25805a226d741c47d274a35ad5c10a7dde175fcddfa511d7cf3da0a21eb3eab7", size = 11223443, upload-time = "2026-06-11T17:55:00.573Z" }, + { url = "https://files.pythonhosted.org/packages/68/58/bd41f7688b2fd5623012605130ed70e60aa7f2244baa3d5066bdd61530c8/ruff-0.15.17-py3-none-macosx_11_0_arm64.whl", hash = "sha256:f6ad73b14c2d18a3bf8ad7cb6974294d7f613a7898604826058e6ac64918ef4d", size = 10566458, upload-time = "2026-06-11T17:55:07.52Z" }, + { url = "https://files.pythonhosted.org/packages/d8/5b/733371013fcf1ec339e477ece6ab42bfe10bdd9bba8ee88a9516aa56bfc0/ruff-0.15.17-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ba0c1e4f95bcb3869d0d30cbd5917071ef2e28665abfec970cdab0492c713ed", size = 10914483, upload-time = "2026-06-11T17:55:05.501Z" }, + { url = "https://files.pythonhosted.org/packages/bd/cc/6f24251cc0252f7239391ccb85833f320efad14ebe5b443943f37ced6332/ruff-0.15.17-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:81647960f10bff57d2e51cadd0c3950fe598400c852863a038720ef5b8cca91e", size = 10647497, upload-time = "2026-06-11T17:54:57.733Z" }, + { url = "https://files.pythonhosted.org/packages/68/dd/0d10c17ce1a1624d6fc3156309c3f834fdb5dfaad026ec90c85684f3990e/ruff-0.15.17-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e01a84ddbc8c16c23055ba3924476850f1bbc1917cebbb9376665a63e74260d", size = 11416967, upload-time = "2026-06-11T17:54:51.461Z" }, + { url = "https://files.pythonhosted.org/packages/2f/91/556bfb156f6144f355e831c23db00b2fc4120f86b3ce81cc5f7fd2df51f3/ruff-0.15.17-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84fe9f653152f8f294f9f7e03bf3a453d8b4a27f7a59c78c8666167f2b17b96c", size = 12335770, upload-time = "2026-06-11T17:54:45.793Z" }, + { url = "https://files.pythonhosted.org/packages/88/82/8b5999aa13355e926f06d9f42a32dcca862f623bf0363785ff89d607dffd/ruff-0.15.17-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c0fe88a7676e7a05b73174d4d4a59cb2ac21ff8263583f87a81a6018475a978", size = 11575441, upload-time = "2026-06-11T17:54:32.661Z" }, + { url = "https://files.pythonhosted.org/packages/11/93/f10377bb04109ca0e8cbc483ff1982c54b6d418210041776f93e8cdc7fa9/ruff-0.15.17-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecfc3c7878fff94633ab0348524e093f9ce3243080416dd7d14f8ba400174719", size = 11557614, upload-time = "2026-06-11T17:54:34.698Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a6/eeeae7f7d5493df41649ab3db92f086b2d0a30199e4efdf8e3dd7a033f24/ruff-0.15.17-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:b8461180b22420b1bdc289909410930761629fddf2a5aaf60fae1ab26cedc4c4", size = 11544450, upload-time = "2026-06-11T17:54:39.042Z" }, + { url = "https://files.pythonhosted.org/packages/32/88/5991ce565129a24dd4a00db1254b3b5db2e53018cbe4018ea5a89738e727/ruff-0.15.17-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6eccbe50a038b503e7140b441aa9c7fc8c1f36edf23ebef9f4165c2f28f568b7", size = 10892524, upload-time = "2026-06-11T17:55:09.432Z" }, + { url = "https://files.pythonhosted.org/packages/f5/1d/0fdd248313425f55223968af04b0a42125466a8d88d21c1d99c6af0a51e8/ruff-0.15.17-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:382fc0521025f5a8ad447d8bdd523545d0d7646adb718eb1c2dac5065ec27c0f", size = 10659573, upload-time = "2026-06-11T17:54:36.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/0e/072e8260deb9461062ce9311ced27a8e541229a6ffd483013dd37661e43e/ruff-0.15.17-py3-none-musllinux_1_2_i686.whl", hash = "sha256:456d41fcd1b2777ad63f09a6e7121d43f7b688bbc76a800c10f7f8fb1f912c3f", size = 11127818, upload-time = "2026-06-11T17:55:03.124Z" }, + { url = "https://files.pythonhosted.org/packages/ab/b4/55060a34163121498014696b5f656db5b8c6963768f227dbf0d76b311073/ruff-0.15.17-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b1a04bcc94ae6194e9db05d16ad31f298a7194bfbcb08258bbe589cee1d587b8", size = 11655901, upload-time = "2026-06-11T17:54:53.562Z" }, + { url = "https://files.pythonhosted.org/packages/49/71/9b29d6b87cef468d697f43c6a91e3fae4a80185779d7d5a4ef27d173439f/ruff-0.15.17-py3-none-win32.whl", hash = "sha256:596065960ab1ff593f744220c9fe6580eda00a95003cffa9f4048bb5b1bf0392", size = 10925574, upload-time = "2026-06-11T17:54:55.723Z" }, + { url = "https://files.pythonhosted.org/packages/3d/b2/8fc77f3723228836fa5d12497eb71c808f83782e10d058d2b15cfa14640b/ruff-0.15.17-py3-none-win_amd64.whl", hash = "sha256:6769e5fa1710b179b92e0bfa5a51735b35baea9013dadb06d5f44cbcf9547084", size = 12058788, upload-time = "2026-06-11T17:54:41.042Z" }, + { url = "https://files.pythonhosted.org/packages/2d/c7/c53e8dbff9c9dc4b7928773421ae294a5d28fcb8dcda1a089579d3a7e510/ruff-0.15.17-py3-none-win_arm64.whl", hash = "sha256:f3be1fbb34bcdfd146240d8fb92a709d4c2c8191348580a3c044ec60fa0b4456", size = 11355275, upload-time = "2026-06-11T17:54:43.635Z" }, ] [[package]] @@ -2558,14 +2558,14 @@ wheels = [ [[package]] name = "starlette" -version = "1.2.1" +version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/44/ec35f1b6e83094b997da438a02c8c9b0ade2b1e84cfc48bd4656780760a6/starlette-1.2.1.tar.gz", hash = "sha256:9b9b5ebb992e67d6093741e63c2f59e4f6fff986f81163c087867bd7b924b3f6", size = 2701854, upload-time = "2026-05-31T01:07:51.847Z" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/1c/54/196d0c1db10af76baa4f64894448505d60d3cdf70ef92cbb35f46a4e4c71/starlette-1.2.1-py3-none-any.whl", hash = "sha256:4de0082d08c8f6764a85a54cf1120d6939507a19905c7768acad2a9f875d2b89", size = 73350, upload-time = "2026-05-31T01:07:50.09Z" }, + { url = "https://files.pythonhosted.org/packages/ec/bb/2799cc2ede3ed41131f8975621e7213dfc7ef4acbbaadfa440f32500c370/starlette-1.3.1-py3-none-any.whl", hash = "sha256:c7372aae11c3c3f26a42df7bd626cec2f47d03483d261d369516a615a53714c6", size = 73632, upload-time = "2026-06-12T09:23:10.017Z" }, ] [[package]] @@ -2711,15 +2711,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.48.0" +version = "0.49.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/bf/f6544ba992ddb9a6077343a576f9844f7f8f06ab819aefd00206e9255f18/uvicorn-0.48.0.tar.gz", hash = "sha256:a5504207195d08c2511bf9125ede5ac4a4b71725d519e758d01dcf0bc2d31c37", size = 91074, upload-time = "2026-05-24T12:08:41.925Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c4/1f/fa18009dea8469069cca78a4e877a008ab78f08b064bfc9ab891579077ff/uvicorn-0.49.0.tar.gz", hash = "sha256:ebf4271aa580d9de97f93192d4595176df6e91f9aae919ca73e4fc07df1e66a3", size = 91284, upload-time = "2026-06-03T22:01:30.448Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/be/72532be3da7acc5fdfbccdb95215cd04f995a0886532a5b423f929cda4cc/uvicorn-0.48.0-py3-none-any.whl", hash = "sha256:48097851328b87ec36117d3d575234519eb58c2b22d79666e9bbc6c49a761dad", size = 71410, upload-time = "2026-05-24T12:08:40.258Z" }, + { url = "https://files.pythonhosted.org/packages/88/fa/e1388bbcf24ef3274f45c0c1c7b501fd14971037c1b6ee23610553307497/uvicorn-0.49.0-py3-none-any.whl", hash = "sha256:ba3d14c3ee7e41c6c654c46c9eb489d33213cdd30aa1696eab1374337c13f68f", size = 71376, upload-time = "2026-06-03T22:01:29.037Z" }, ] [package.optional-dependencies] @@ -2764,7 +2764,7 @@ wheels = [ [[package]] name = "virtualenv" -version = "21.4.2" +version = "21.4.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "distlib" }, @@ -2772,9 +2772,9 @@ dependencies = [ { name = "platformdirs" }, { name = "python-discovery" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0d/4e93c8e6d1001a75763f87d8f5ecda8ebc7f4aa2153dddfaf4ae8892821a/virtualenv-21.4.2.tar.gz", hash = "sha256:38e6ee0a555615c0ea9da2ac7e9998fe8dc3b911dd33ad8eaad2020957653b0c", size = 7613326, upload-time = "2026-05-31T17:01:22.827Z" } +sdist = { url = "https://files.pythonhosted.org/packages/4b/50/7564c805bb8966d9771caaba8a143fa5e57c848ce4e7fdf2d55a1feb2ead/virtualenv-21.4.3.tar.gz", hash = "sha256:938ff0fd3f4e0f0d3a025f67a3d2f25e3c3aabbcd5857ea6170619138d72d141", size = 7644454, upload-time = "2026-06-11T16:47:04.843Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/bf/c4/557dc082be035381b85fdb2b74e21d3d21b57750b74f2b47a32f3a639ff9/virtualenv-21.4.2-py3-none-any.whl", hash = "sha256:854210ca524a1a4d0d744734f4acbc721c3ffe163b85bbf5d56d14d5ae2f0fae", size = 7594079, upload-time = "2026-05-31T17:01:20.735Z" }, + { url = "https://files.pythonhosted.org/packages/a2/8d/84b0d07c6b5f685f85ddf6c87a59d3a8a895a3dfd89e759666fabe951b94/virtualenv-21.4.3-py3-none-any.whl", hash = "sha256:75f4127d4067397c64f38579ce918fec6bf9ca2cd4f48685e82952cc3c035840", size = 7625544, upload-time = "2026-06-11T16:47:01.78Z" }, ] [[package]] @@ -2840,11 +2840,11 @@ wheels = [ [[package]] name = "wcwidth" -version = "0.7.0" +version = "0.8.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/2c/ee/afaf0f85a9a18fe47a67f1e4422ed6cf1fe642f0ae0a2f81166231303c52/wcwidth-0.7.0.tar.gz", hash = "sha256:90e3a7ea092341c44b99562e75d09e4d5160fe7a3974c6fb842a101a95e7eed0", size = 182132, upload-time = "2026-05-02T16:04:12.653Z" } +sdist = { url = "https://files.pythonhosted.org/packages/49/b4/51fe890511f0f242d07cb1ebe6a5b6db417262b9d2568b460347c57d95cc/wcwidth-0.8.1.tar.gz", hash = "sha256:faf5b4a5366a72dc49cad48cdf21f52bdf63bdda995178e483ba247ff79089b9", size = 1466072, upload-time = "2026-06-08T05:57:23.146Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/52/e465037f5375f43533d1a80b6923955201596a99142ed524d77b571a1418/wcwidth-0.7.0-py3-none-any.whl", hash = "sha256:5d69154c429a82910e241c738cd0e2976fac8a2dd47a1a805f4afed1c0f136f2", size = 110825, upload-time = "2026-05-02T16:04:11.033Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6e/95b0e537de1f4d4301f76f944642c6da50d1511cc7b3d64dc418a66c7509/wcwidth-0.8.1-py3-none-any.whl", hash = "sha256:f453740b1e4a4f3291faa37944c555d71056c4da08d59809b307ef4feba695c8", size = 323092, upload-time = "2026-06-08T05:57:21.413Z" }, ] [[package]] @@ -2970,17 +2970,18 @@ wheels = [ [[package]] name = "zopfli" -version = "0.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/05/4d/b5a8c14cfc7beb5dd798f316418126b5107a54d5f9ba322ad874089b91ce/zopfli-0.4.2.tar.gz", hash = "sha256:a75e646fed3a2a42a82e69a81644009189c8ab4271691f020d52da8630d0580e", size = 179062, upload-time = "2026-05-26T11:00:52.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/dd/f2b25f7dd657db0fdd0436ea4caa0f5709132d65728bfb2d48ee11bc8bf7/zopfli-0.4.2-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:d1972b58083b85af460d8936f623d849b487c151b26eae925b25ec921ae6cd22", size = 291485, upload-time = "2026-05-26T11:00:28.601Z" }, - { url = "https://files.pythonhosted.org/packages/38/fc/b50b1cc4d192953552751b3ed809a68c005392e14aefd78f63067fb7493f/zopfli-0.4.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:932083f7ca190fbd73cdf8ad7d32ec7231ecd25e1b3fade547cfb11b823ff91f", size = 829353, upload-time = "2026-05-26T11:00:31.91Z" }, - { url = "https://files.pythonhosted.org/packages/bb/74/ff2a9351738fd6ec86249c4daaff3e4afb0deb3a8bff3640f3c6f3212a2b/zopfli-0.4.2-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:18af6d2f778552d9bfdaa8e6caaf38c2bd57d0efba34a47860fcc4f6ba899696", size = 818434, upload-time = "2026-05-26T11:00:30.279Z" }, - { url = "https://files.pythonhosted.org/packages/3c/dd/fe32b457a95f4f75e96bba99d86935c3c5be988b1389c85cf4bbe2194844/zopfli-0.4.2-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:65a847b1f234df456584f0267fb0f270a95772e675a98ae9c21f3b4839077b2f", size = 1777947, upload-time = "2026-05-26T11:00:33.697Z" }, - { url = "https://files.pythonhosted.org/packages/73/ec/0959952a13124b5d58829f808daabe2d2e0358d25b33f7460366ddab21ce/zopfli-0.4.2-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:70c20595aa30aae246ac71a9fa471e2aa768318150ab814aeea2f651c59c6a32", size = 1863865, upload-time = "2026-05-26T11:00:35.297Z" }, - { url = "https://files.pythonhosted.org/packages/38/0e/11dab5379262c9b19ec9a2d8c0bc4314f62a47047ac6f54912a2e0fb82df/zopfli-0.4.2-cp310-abi3-win32.whl", hash = "sha256:d3bc0b483575ab8849d9c15b349f78ae0141eb4dfe2ba260c8fdc0b3ba5c6c42", size = 82229, upload-time = "2026-05-26T11:00:38.07Z" }, - { url = "https://files.pythonhosted.org/packages/04/f6/f75c781c1464045a3c465625e813605636f09e5fb2e15494eeee5263f8ef/zopfli-0.4.2-cp310-abi3-win_amd64.whl", hash = "sha256:bc25a3b3568910afb4bbd951d99835de29cade95417bca215339eac172eb381d", size = 102103, upload-time = "2026-05-26T11:00:36.842Z" }, +version = "0.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/74/21/3b6af43a663b22b00e738bb0642931a2579e15da6852613d56c6aa535d28/zopfli-0.4.3.tar.gz", hash = "sha256:d3a50f91a13cea9bafe025de8fd87a005eb26de02a4f0c193127ddbf23ac8ebe", size = 179156, upload-time = "2026-06-10T09:10:19.96Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/5f/b7d81b670daf990e15a0f7551da96c3c0700f69ae6d96b0245d6a19f51f3/zopfli-0.4.3-cp310-abi3-macosx_10_9_universal2.whl", hash = "sha256:88f4fbe429aad72bc206275d81fab11a097e0f951a5848d1f51083c37ea73073", size = 291492, upload-time = "2026-06-10T09:10:06.621Z" }, + { url = "https://files.pythonhosted.org/packages/55/c8/d8d8d731e0b192024567b7198fb77b748821d355f3c8bf0109de27191f43/zopfli-0.4.3-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:769875152d0625c46707bcca57d4b2233fe653482067acd55fbf6ec525cb9bdc", size = 829354, upload-time = "2026-06-10T09:10:07.909Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2b/fbe8ba2ec40f5986b8983a4752f7a32672a80a10ea6e68213324a7055469/zopfli-0.4.3-cp310-abi3-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0c9c1d40a8cb1d58762d7e57290ccb753e0828c4d01be8acb59aae5d0ca206", size = 818436, upload-time = "2026-06-10T09:10:09.063Z" }, + { url = "https://files.pythonhosted.org/packages/de/d9/63568c54c8b68b9135f3456c5add83797a5528d596657f0e4f4910173b08/zopfli-0.4.3-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:7fa3c35193475290e3f007bbcdebdbae64ba2f012d75c632da0d727e1da50d5e", size = 1778931, upload-time = "2026-06-10T09:10:10.282Z" }, + { url = "https://files.pythonhosted.org/packages/7a/05/8f3aac10a858e89c2146d3a1f6ce33634c3db757365b4148fef1b85784d2/zopfli-0.4.3-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:47604eee5c6704bdf0e94d8391fe3b74ddb2abd84128fbcfdc3ee0fc265feaef", size = 1864132, upload-time = "2026-06-10T09:10:11.595Z" }, + { url = "https://files.pythonhosted.org/packages/8d/20/9ca59d14b91f9fbc631793b4b085b309777edadaca496aa518a180817827/zopfli-0.4.3-cp310-abi3-win32.whl", hash = "sha256:628c3e941752880b3491db8d44163d0aedb221944e22a17187ff7fc549b050f6", size = 271715, upload-time = "2026-06-10T09:10:12.7Z" }, + { url = "https://files.pythonhosted.org/packages/9d/3a/4ff4fdead77ef30f5832b38a47eb7a1283e98b3c678576b83f8fdfff53eb/zopfli-0.4.3-cp310-abi3-win_amd64.whl", hash = "sha256:921c2c9907f4364963848da5ad194b46d68865e07fdb975d04fd09bc42d47357", size = 288550, upload-time = "2026-06-10T09:10:13.639Z" }, + { url = "https://files.pythonhosted.org/packages/e6/44/6264f929057236fde72dd6d271f54612b4811ce37288e002f5d5339d696a/zopfli-0.4.3-cp310-abi3-win_arm64.whl", hash = "sha256:7e9703ca6e7ef66c8d05e0826b6f558b680c9db8206f84f05a3ee93430a12e42", size = 451343, upload-time = "2026-06-10T09:10:14.72Z" }, ] [[package]] From cbac3e4e8ecfc73f0c85ad61e412272a1d9e4083 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 16:13:07 +0300 Subject: [PATCH 28/31] chore(deps): npm audit fix --- kompassi-v2-frontend/package-lock.json | 647 +++++++++++++++++-------- 1 file changed, 449 insertions(+), 198 deletions(-) diff --git a/kompassi-v2-frontend/package-lock.json b/kompassi-v2-frontend/package-lock.json index 0356d7387..1b784d5a3 100644 --- a/kompassi-v2-frontend/package-lock.json +++ b/kompassi-v2-frontend/package-lock.json @@ -130,9 +130,9 @@ } }, "node_modules/@ardatan/relay-compiler": { - "version": "12.0.3", - "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.0.3.tgz", - "integrity": "sha512-mBDFOGvAoVlWaWqs3hm1AciGHSQE1rqFc/liZTyYz/Oek9yZdT5H26pH2zAFuEiTiBVPPyMuqf5VjOFPI2DGsQ==", + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.3.0.tgz", + "integrity": "sha512-lc6PyM1IQCSa87DMChfv61HuhrSquHGhsF+WFSm2csFnKMSHaj0S1M8fnGr04i7O9YnwyR+OcgQ3CfzlEPC9Fg==", "dev": true, "license": "MIT", "dependencies": { @@ -141,7 +141,7 @@ "@babel/runtime": "^7.26.10", "chalk": "^4.0.0", "fb-watchman": "^2.0.0", - "immutable": "~3.7.6", + "immutable": "^5.1.5", "invariant": "^2.2.4", "nullthrows": "^1.1.1", "relay-runtime": "12.0.0", @@ -1076,64 +1076,34 @@ "dev": true, "license": "MIT" }, - "node_modules/@formatjs/ecma402-abstract": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.4.tgz", - "integrity": "sha512-qrycXDeaORzIqNhBOx0btnhpD1c+/qFIHAN9znofuMJX6QBwtbrmlpWfD4oiUUD2vJUOIYFA/gYtg2KAMGG7sA==", - "license": "MIT", - "dependencies": { - "@formatjs/fast-memoize": "2.2.7", - "@formatjs/intl-localematcher": "0.6.1", - "decimal.js": "^10.4.3", - "tslib": "^2.8.0" - } - }, - "node_modules/@formatjs/ecma402-abstract/node_modules/@formatjs/intl-localematcher": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.6.1.tgz", - "integrity": "sha512-ePEgLgVCqi2BBFnTMWPfIghu6FkbZnnBVhO2sSxvLfrdFw7wCHAHiDoM2h4NRgjbaY7+B7HgOLZGkK187pZTZg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.8.0" - } - }, "node_modules/@formatjs/fast-memoize": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz", - "integrity": "sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ==", - "license": "MIT", - "dependencies": { - "tslib": "^2.8.0" - } + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.1.6.tgz", + "integrity": "sha512-H5aexk1Le7T9TPmscacZ+1pR6CTa2n1wq+HDVGXhH8TzUlQQpeXzZs91dRtmFHrbeNbjPFPfQujUqm7MHgVoXQ==", + "license": "MIT" }, "node_modules/@formatjs/icu-messageformat-parser": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.2.tgz", - "integrity": "sha512-AfiMi5NOSo2TQImsYAg8UYddsNJ/vUEv/HaNqiFjnI3ZFfWihUtD5QtuX6kHl8+H+d3qvnE/3HZrfzgdWpsLNA==", + "version": "3.5.11", + "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-3.5.11.tgz", + "integrity": "sha512-NVsuNsc2dUVG9+4HBJ/srScxtA/18LqGgwtop/tuN/OIBjVl6QA+0KhfZQddDD9sEh2LeVjLFPGVU3ixa3blcA==", "license": "MIT", "dependencies": { - "@formatjs/ecma402-abstract": "2.3.4", - "@formatjs/icu-skeleton-parser": "1.8.14", - "tslib": "^2.8.0" + "@formatjs/icu-skeleton-parser": "2.1.10" } }, "node_modules/@formatjs/icu-skeleton-parser": { - "version": "1.8.14", - "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.14.tgz", - "integrity": "sha512-i4q4V4qslThK4Ig8SxyD76cp3+QJ3sAqr7f6q9VVfeGtxG9OhiAk3y9XF6Q41OymsKzsGQ6OQQoJNY4/lI8TcQ==", - "license": "MIT", - "dependencies": { - "@formatjs/ecma402-abstract": "2.3.4", - "tslib": "^2.8.0" - } + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-2.1.10.tgz", + "integrity": "sha512-XuSva+8ZGawk8VnD5VD6UeH8KarQ/Z022zgjHDoHmlNiAewstXuuzXc0Hk5pGFSdG+nNw5bfJKXqj1ZXHn9yUA==", + "license": "MIT" }, "node_modules/@formatjs/intl-localematcher": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.5.10.tgz", - "integrity": "sha512-af3qATX+m4Rnd9+wHcjJ4w2ijq+rAVP3CCinJQvFv1kgSu1W6jypUmvleJxcewdxmutM8dmIRZFxO/IQBZmP2Q==", + "version": "0.8.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.8.10.tgz", + "integrity": "sha512-P/IC3qws3jH+1fEs+o0RIFgXKRaQlFehjS5W0FPAqdo6hgzawLl+eD0q0JjheQ3XtoOe5n8WSYfX06KQZI/QJA==", "license": "MIT", "dependencies": { - "tslib": "2" + "@formatjs/fast-memoize": "3.1.6" } }, "node_modules/@graphql-codegen/add": { @@ -2598,9 +2568,9 @@ } }, "node_modules/@next/env": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.14.tgz", - "integrity": "sha512-aXeirLYuASxEgi4X4WhfXsShCFxWDfNn/8ZeC5YXAS2BB4A8FJi1kwwGL6nvMVboE7fZCzmJPNdMvVHc8JpaiA==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.19.tgz", + "integrity": "sha512-sWWluFvcv5v3Fxznmf2ZfjyoVQt/64oCnYqS90inQWGzMPK1VjvekPiz3OPHKmFT30EnHrjlbyaHLt3M0vWabw==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -2614,9 +2584,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.14.tgz", - "integrity": "sha512-Y9K6SPzobnZvrRDPO2s0grgzC+Egf0CqfbdvYmQVaztV890zicw8Z8+4Vqw8oPck8r1TjUHxVh8299Cg4TrxXg==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.19.tgz", + "integrity": "sha512-jx9wWlTKueHKPvVOndyr7WuaevWCkuYqsQ8gC0TMPKAVWG3MhcdMrjfo9tvIZNXd0QOUYXXvAcZ325y8Uq7uzg==", "cpu": [ "arm64" ], @@ -2630,9 +2600,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.14.tgz", - "integrity": "sha512-aNnkSMjSFRTOmkd7qoNI2/rETQm/vKD6c/Ac9BZGa9CtoOzy3c2njgz7LvebQJ8iPxdeTuGnAjagyis8a9ifBw==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.19.tgz", + "integrity": "sha512-291KFcsIQ3OenRdiUDFOR6W3wezzH4auENXm1gbm1Bjd4ANMMRgxPrWTUztQN43BnVoVuMnHCrLeECIMwgFKbA==", "cpu": [ "x64" ], @@ -2646,12 +2616,15 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.14.tgz", - "integrity": "sha512-tjlpia+yStPRS//6sdmlVwuO1Rioern4u2onafa5n+h2hCS9MAvMXqpVbSrjgiEOoCs0nJy7oPOmWgtRRNSM5Q==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.19.tgz", + "integrity": "sha512-WeH+nelQyyMeE2f8FxBRZNrGipya5zHZV2vjzfCOAYyiI6am+NbnWAAldOBFQBB2w0DjJcsvrKqoFT2b7+5YoA==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2662,12 +2635,15 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.14.tgz", - "integrity": "sha512-8B8cngBaLadl5lbDRdxGCP1Lef8ipD6KlxS3v0ElDAGil6lafrAM3B258p1KJOglInCVFUjk751IXMr2ixeQOQ==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.19.tgz", + "integrity": "sha512-5xTOE0lDlDCSSfp+BAif7j17VRRCjWp//ZPZy6NI0QpdrhxtQnsZguSx0xAAZ0c9XZLrLLwCe/XVe5YPrRilKw==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2678,12 +2654,15 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.14.tgz", - "integrity": "sha512-bAS6tIAg8u4Gn3Nz7fCPpSoKAexEt2d5vn1mzokcqdqyov6ZJ6gu6GdF9l8ORFrBuRHgv3go/RfzYz5BkZ6YSQ==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.19.tgz", + "integrity": "sha512-LTxRmMgqqMv05Had879W00Fm53quiJd3Zuz8h1JSNJ3nGSlbZ/7Tjs1tKyScgN3Au3t3MyPsjPlq60fMmSHLsg==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2694,12 +2673,15 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.14.tgz", - "integrity": "sha512-mMxv/FcrT7Gfaq4tsR22l17oKWXZmH/lVqcvjX0kfp5I0lKodHYLICKPoX1KRnnE+ci6oIUdriUhuA3rBCDiSw==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.19.tgz", + "integrity": "sha512-eoNQSpA5PQfB9wBO4RA47MTDXWz1fizy9Y3Z6e4DetYIF3dvjuu8sj7aIGn/bFCU6lnFzTK34NtCaffP4NsQ7Q==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2710,9 +2692,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.14.tgz", - "integrity": "sha512-OTmiBlYThppnvnsqx0rBqjDRemlmIeZ8/o4zI7veaXoeO1PVHoyj2lfTfXTiiGjCyRDhA10y4h6ZvZvBiynr2g==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.19.tgz", + "integrity": "sha512-6UNt2dFuCHOe446sm/Kp69nUe8/wIhnh9bm6Xcqw4qEWCOppLMOvhTBVgvM7invVUNr4SPpP6NOQsACtn2IN9Q==", "cpu": [ "arm64" ], @@ -2726,9 +2708,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.14.tgz", - "integrity": "sha512-+W7eFf3RS7m4G6tppVTOSyP9Y6FsJXfOuKzav1qKniiFm3KFByQfPEcouHdjlZmysl4zJGuGLQ/M9XyVeyeNEg==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.19.tgz", + "integrity": "sha512-PhmojAHyqMne56HBLGu9dhDnHPuFmEjrXSQMM/nW0J6j849lk3ESrVtqNJcCk8CKOV7brpTTbaYAjwKPzKM69w==", "cpu": [ "x64" ], @@ -2802,7 +2784,6 @@ "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", - "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -2841,7 +2822,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2862,7 +2842,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2883,7 +2862,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2904,7 +2882,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2925,7 +2902,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2946,7 +2922,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2967,7 +2942,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -2988,7 +2962,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3009,7 +2982,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3030,7 +3002,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3051,7 +3022,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3072,7 +3042,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3093,7 +3062,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -3108,10 +3076,9 @@ } }, "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -3226,6 +3193,222 @@ "integrity": "sha512-bXHSaW5jRTmke9Vd0h5P7BtWZG9Znqb8gSDxZnxaGSJnGwPLDPfS+3g0BKzeWqzgZPsIVZkM7m2tbo18cm5HBw==", "license": "MIT" }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.41.tgz", + "integrity": "sha512-kREh6J5paQFvP3i7f/4FbqRNOJREutVFVOkder4GVyCBQ39YmER55cW/y1NNjwrchzFqgYswFn0mMDCqbqKzrw==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.15.41.tgz", + "integrity": "sha512-N8B56ESFazZAWZyIkecADSPCwlLEinW7QLMEeotCpv4J7VXwfH+OLkmRL8o96UZ+1355fwHxDTS6/wK7yucvkA==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.41.tgz", + "integrity": "sha512-6XrId2fyle0mS5xxON8rU84mPd2Cq1kDJRj+4BnQKTd7u+2kSA6Ww+JkOP0iTNqOqt9OXhPOEAjBHAuonWcdCg==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.41.tgz", + "integrity": "sha512-ynLIarxlkVnqHn1D0fKOVht6mNU5ks6lrH+MY3kkS+XFaGGgDxFZVjWKJlkYTKm3RCvBTfA8Ng5fLufXheMRKQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.41.tgz", + "integrity": "sha512-dXu/5vd4gh8symyhRF+4G7gOPkjmb4pONhh7sl+6GSiW0LOKZlfu5kXmyFbTz9smOT7jgr002qY9b1nujjXt2A==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.15.41.tgz", + "integrity": "sha512-XGO6zVPXoPE0gf/XnI4jBbafNT13AYgoh6ns0JCSdOetI/kqVf0vhpz7NuNgAzZrMVCsmieqjPoTwViDgh4mOQ==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.15.41.tgz", + "integrity": "sha512-0WUglRwyZtW+iMi7J3iFdrCxreZZIKf4egTwEQfIYRsqFax69A0OrFj+NIoFSE03xBT/IFRrg+S8K6f9Ky+4hA==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.41.tgz", + "integrity": "sha512-VxkuQK59c0tHm6uJZCUrS3cyA2JhGGfdU6e41SZz0x/JS+4Sm7C1mIc97In14vkZJopEt7yXA2TouCqZDSygEA==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.41.tgz", + "integrity": "sha512-/0qXIu1ZxggLuovLb22vFfKHq2AA4n6Whw5UwmVCHk4pkw7KWnPIQpMCEqUMPsNkFJig7PPp/TSYFu8ZEb2rtQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.41.tgz", + "integrity": "sha512-Y481sMNZM6rECh9VO4+y26N1lWEDAyxnBZskUf37fl90uHE946VHfmiVQWT0uMFOhyJJFovGTRuF4W82dwewUg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.41.tgz", + "integrity": "sha512-BAchBD5qeUzy3hiPSLJtaaoSm4blCLyYffOF1bGE4ETcV+OisqjUAwDQMJj++4bTpvMCDzwC+Bj3PmQyBCtscw==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.41.tgz", + "integrity": "sha512-WOkA+fJ/ViVBQDsSV9JC52NACTe5PhlurA6viASDZGb7HR3KS01ZG7RZ+Bg6SVQFIoq3gSbTsskQVe6EbHFAYw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "license": "Apache-2.0" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", @@ -3235,6 +3418,15 @@ "tslib": "^2.8.0" } }, + "node_modules/@swc/types": { + "version": "0.1.26", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.26.tgz", + "integrity": "sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==", + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, "node_modules/@tabby_ai/hijri-converter": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@tabby_ai/hijri-converter/-/hijri-converter-1.0.5.tgz", @@ -3552,9 +3744,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -3592,13 +3784,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -4084,9 +4276,9 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -4472,9 +4664,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -5192,12 +5384,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "license": "MIT" - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5287,7 +5473,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "devOptional": true, "license": "Apache-2.0", "engines": { "node": ">=8" @@ -6267,9 +6452,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" }, @@ -6600,9 +6785,9 @@ } }, "node_modules/graphql-config/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -6620,13 +6805,13 @@ } }, "node_modules/graphql-config/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -6850,6 +7035,21 @@ "node": ">=0.10.0" } }, + "node_modules/icu-minify": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/icu-minify/-/icu-minify-4.13.0.tgz", + "integrity": "sha512-SIFMeUHZJjzS5RvIGvybKvWoHjDm9cGVEs2EpJ8PmywOdJLWyblPm7TdPLLoUtkJtwQD7iGhl2WMptZ+N0on+w==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], + "license": "MIT", + "dependencies": { + "@formatjs/icu-messageformat-parser": "^3.4.0" + } + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -6882,14 +7082,11 @@ } }, "node_modules/immutable": { - "version": "3.7.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", - "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.8.0" - } + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", + "devOptional": true, + "license": "MIT" }, "node_modules/import-fresh": { "version": "3.3.1", @@ -7001,15 +7198,13 @@ } }, "node_modules/intl-messageformat": { - "version": "10.7.16", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-10.7.16.tgz", - "integrity": "sha512-UmdmHUmp5CIKKjSoE10la5yfU+AYJAaiYLsodbjL4lji83JNvgOQUjGaGhGrpFCb0Uh7sl7qfP1IyILa8Z40ug==", + "version": "11.2.8", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-11.2.8.tgz", + "integrity": "sha512-l323RCl3qJDVQ8U9j74ut/hVMdg3VPsOHpVMDvFfz9qiq4dPO5ooVYFNVUzzrpgG39a+RLzcXyJb8VFgIU+tUA==", "license": "BSD-3-Clause", "dependencies": { - "@formatjs/ecma402-abstract": "2.3.4", - "@formatjs/fast-memoize": "2.2.7", - "@formatjs/icu-messageformat-parser": "2.11.2", - "tslib": "^2.8.0" + "@formatjs/fast-memoize": "3.1.6", + "@formatjs/icu-messageformat-parser": "3.5.11" } }, "node_modules/invariant": { @@ -7204,7 +7399,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -7259,7 +7453,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8019,9 +8212,9 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -8147,12 +8340,12 @@ } }, "node_modules/next": { - "version": "15.5.14", - "resolved": "https://registry.npmjs.org/next/-/next-15.5.14.tgz", - "integrity": "sha512-M6S+4JyRjmKic2Ssm7jHUPkE6YUJ6lv4507jprsSZLulubz0ihO2E+S4zmQK3JZ2ov81JrugukKU4Tz0ivgqqQ==", + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.19.tgz", + "integrity": "sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==", "license": "MIT", "dependencies": { - "@next/env": "15.5.14", + "@next/env": "15.5.19", "@swc/helpers": "0.5.15", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", @@ -8165,14 +8358,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.5.14", - "@next/swc-darwin-x64": "15.5.14", - "@next/swc-linux-arm64-gnu": "15.5.14", - "@next/swc-linux-arm64-musl": "15.5.14", - "@next/swc-linux-x64-gnu": "15.5.14", - "@next/swc-linux-x64-musl": "15.5.14", - "@next/swc-win32-arm64-msvc": "15.5.14", - "@next/swc-win32-x64-msvc": "15.5.14", + "@next/swc-darwin-arm64": "15.5.19", + "@next/swc-darwin-x64": "15.5.19", + "@next/swc-linux-arm64-gnu": "15.5.19", + "@next/swc-linux-arm64-musl": "15.5.19", + "@next/swc-linux-x64-gnu": "15.5.19", + "@next/swc-linux-x64-musl": "15.5.19", + "@next/swc-win32-arm64-msvc": "15.5.19", + "@next/swc-win32-x64-msvc": "15.5.19", "sharp": "^0.34.3" }, "peerDependencies": { @@ -8199,9 +8392,9 @@ } }, "node_modules/next-auth": { - "version": "4.24.13", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.13.tgz", - "integrity": "sha512-sgObCfcfL7BzIK76SS5TnQtc3yo2Oifp/yIpfv6fMfeBOiBJkDWF3A2y9+yqnmJ4JKc2C+nMjSjmgDeTwgN1rQ==", + "version": "4.24.14", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.24.14.tgz", + "integrity": "sha512-YRz6xFDXKUwiXSMMChbrBEWyFktZ1qZXEgeSHQQ3nsy08B4c/xLk6REeutRsIFwkjY/1+ShHnu07DN3JeJguig==", "license": "ISC", "dependencies": { "@babel/runtime": "^7.20.13", @@ -8249,9 +8442,9 @@ } }, "node_modules/next-intl": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.3.11.tgz", - "integrity": "sha512-kyjeGUuLBU1DqDVAzhgoltYxQ8esVqqqkq2BRKPFxTwHPT9r5P5ZHePu3esjc5B3dVeVC/yFf8ebEnaYo68q1g==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/next-intl/-/next-intl-4.13.0.tgz", + "integrity": "sha512-OvNq2v5XLx4EkQOsAhVE9g+6zdb83XHusADCXXtIW4LILYnjEVaeINdr1lkVWKSjzwNUiMSlH5N4K0OQTRiv6A==", "funding": [ { "type": "individual", @@ -8260,14 +8453,18 @@ ], "license": "MIT", "dependencies": { - "@formatjs/intl-localematcher": "^0.5.4", + "@formatjs/intl-localematcher": "^0.8.1", + "@parcel/watcher": "^2.4.1", + "@swc/core": "^1.15.2", + "icu-minify": "^4.13.0", "negotiator": "^1.0.0", - "use-intl": "^4.3.11" + "next-intl-swc-plugin-extractor": "^4.13.0", + "po-parser": "^2.1.1", + "use-intl": "^4.13.0" }, "peerDependencies": { - "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0", - "typescript": "^5.0.0" + "next": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -8275,6 +8472,52 @@ } } }, + "node_modules/next-intl-swc-plugin-extractor": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/next-intl-swc-plugin-extractor/-/next-intl-swc-plugin-extractor-4.13.0.tgz", + "integrity": "sha512-6S/fJI0KXvLCL8nhBo9P8eGaJPzmwJBTCzX0NaUIj0VyU8U89d//T+vjMLdNIXl5MlLaYH7B9MbAjb8Mvu+tqQ==", + "license": "MIT" + }, + "node_modules/next-intl/node_modules/@swc/core": { + "version": "1.15.41", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.15.41.tgz", + "integrity": "sha512-03nQq/082QRJJiOvp3FGbgxTGyyxMxohPTjhk/W9bD2J0tk4ukITI7goOhOO2WbaHn/lsPmo/zf8+DIXhwpgYQ==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.26" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.15.41", + "@swc/core-darwin-x64": "1.15.41", + "@swc/core-linux-arm-gnueabihf": "1.15.41", + "@swc/core-linux-arm64-gnu": "1.15.41", + "@swc/core-linux-arm64-musl": "1.15.41", + "@swc/core-linux-ppc64-gnu": "1.15.41", + "@swc/core-linux-s390x-gnu": "1.15.41", + "@swc/core-linux-x64-gnu": "1.15.41", + "@swc/core-linux-x64-musl": "1.15.41", + "@swc/core-win32-arm64-msvc": "1.15.41", + "@swc/core-win32-ia32-msvc": "1.15.41", + "@swc/core-win32-x64-msvc": "1.15.41" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, "node_modules/no-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", @@ -8290,7 +8533,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "license": "MIT" }, "node_modules/node-domexception": { @@ -8840,9 +9082,9 @@ "license": "ISC" }, "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": { @@ -8852,6 +9094,12 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/po-parser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/po-parser/-/po-parser-2.1.1.tgz", + "integrity": "sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==", + "license": "MIT" + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -9468,13 +9716,6 @@ "@parcel/watcher": "^2.4.1" } }, - "node_modules/sass/node_modules/immutable": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz", - "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==", - "devOptional": true, - "license": "MIT" - }, "node_modules/scheduler": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", @@ -10181,9 +10422,9 @@ } }, "node_modules/tinyglobby/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": { @@ -10424,7 +10665,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, + "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -10629,14 +10870,21 @@ "license": "MIT" }, "node_modules/use-intl": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.3.11.tgz", - "integrity": "sha512-cSOPKwVjaB5Y22vnrVMio5qRolBADe+TYiqsW0/jLqRn6MUNRNBparEDfx12F170ruBWhzcdW6+v6j+MlWGbEQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/use-intl/-/use-intl-4.13.0.tgz", + "integrity": "sha512-fAFDrWaASxlhXOipcOyb5VDD+YONqj6+8O8EcG/J7RBoOUF3A8YahRWLN+mBxYMrlMQB8N6Voqk5X+YC+HSL0A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/amannn" + } + ], "license": "MIT", "dependencies": { - "@formatjs/fast-memoize": "^2.2.0", + "@formatjs/fast-memoize": "^3.1.0", "@schummar/icu-type-parser": "1.21.5", - "intl-messageformat": "^10.5.14" + "icu-minify": "^4.13.0", + "intl-messageformat": "^11.1.0" }, "peerDependencies": { "react": "^17.0.0 || ^18.0.0 || >=19.0.0-rc <19.0.0 || ^19.0.0" @@ -10650,9 +10898,9 @@ "license": "MIT" }, "node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", "funding": [ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" @@ -10850,10 +11098,10 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -10889,9 +11137,9 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", - "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", "dev": true, "license": "ISC", "bin": { @@ -10899,6 +11147,9 @@ }, "engines": { "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, "node_modules/yaml-ast-parser": { From f8df096c2307a7ef62788e6c0a835c8e5ab1bdde Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 16:25:29 +0300 Subject: [PATCH 29/31] chore(emprinten): do not create dummy event and emprinten dummy project by default --- kompassi/core/management/commands/setup.py | 3 --- kompassi/emprinten/README.md | 9 +++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 kompassi/emprinten/README.md diff --git a/kompassi/core/management/commands/setup.py b/kompassi/core/management/commands/setup.py index 3eeec1490..d3a8857d6 100644 --- a/kompassi/core/management/commands/setup.py +++ b/kompassi/core/management/commands/setup.py @@ -65,8 +65,6 @@ def handle(self, *args, **options): event_commands = [command for command in (f"setup_{event}" for event in events) if command in commands] management_commands = [ - # (('kompassi_i18n', '-acv2'), dict()), - # (('collectstatic',), dict(interactive=False)), (("migrate",), dict(interactive=False)), # must come before other setup_* commands because they may emit event log entries (("setup_event_log_v2",), dict()), @@ -75,7 +73,6 @@ def handle(self, *args, **options): (("setup_labour_common_qualifications",), dict()), (("setup_api_v2",), dict()), (("setup_access",), dict()), - (("setup_emprinten",), dict()), (("setup_program_v2",), dict()), ] diff --git a/kompassi/emprinten/README.md b/kompassi/emprinten/README.md new file mode 100644 index 000000000..4d707e1d9 --- /dev/null +++ b/kompassi/emprinten/README.md @@ -0,0 +1,9 @@ +# Emprinten – Generic PDF printer using HTML templates + +Used for work references, invoices and similar. + +## Getting started + +The Emprinten dummy event & example project are no longer created by default in `manage.py setup`. To create these, use + + docker exec backend python manage.py setup_emprinten From 952d8f42be66634775249c4471a98fc0c461a643 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 17:21:58 +0300 Subject: [PATCH 30/31] chore: run eslint on node 24 --- .github/workflows/lint.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index ade72de1e..e7d1d3dbd 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -34,7 +34,7 @@ jobs: - uses: actions/setup-node@v5 with: - node-version: 22 + node-version: 24 cache: npm cache-dependency-path: kompassi-v2-frontend/package-lock.json From bd85b985f1225e6dce7ee275a5a25e475d781e14 Mon Sep 17 00:00:00 2001 From: Luka Pajukanta Date: Fri, 12 Jun 2026 17:22:27 +0300 Subject: [PATCH 31/31] chore: run frontend build on node 24 --- .github/workflows/frontend.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 296fb3875..554996d3f 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -73,7 +73,7 @@ jobs: path: kompassi-v2-frontend/ - uses: actions/setup-node@v5 with: - node-version: 22 + node-version: 24 cache: npm cache-dependency-path: kompassi-v2-frontend/package-lock.json @@ -111,7 +111,7 @@ jobs: path: kompassi-v2-frontend/ - uses: actions/setup-node@v5 with: - node-version: 22 + node-version: 24 cache: npm cache-dependency-path: kompassi-v2-frontend/package-lock.json