mirror of
https://github.com/pretix/pretix.git
synced 2026-11-09 01:14:25 +00:00
Start with custom google pass layout
This commit is contained in:
1 parent
b23a74f3b0
commit
ac2d25ba9a
3 files changed
+332
-176
No files matched your search
@@ -121,7 +121,7 @@ def get_preview_position(event):
|
||||
raise RuntimeError("get_preview_position needs to be called in a rolledback_transaction")
|
||||
|
||||
item = event.items.create(name=LazyI18nString.from_gettext("Sample product"), default_price=Decimal('42.23'),
|
||||
description=_("Sample product description"))
|
||||
description=LazyI18nString.from_gettext("Sample product description"))
|
||||
item2 = event.items.create(name=LazyI18nString.from_gettext("Sample workshop"), default_price=Decimal('23.40'))
|
||||
item.program_times.create(item=item, start=datetime(2017, 12, 27, 0, 0, 0, tzinfo=timezone.utc),
|
||||
end=datetime(2017, 12, 28, 0, 0, 0, tzinfo=timezone.utc))
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from pretix.plugins.wallet.styles.base import PassStyle
|
||||
|
||||
from .apple import ApplePlatform, AppleWalletEventTicket
|
||||
from .google import GooglePlatform, GoogleWalletDefaultEventTicket
|
||||
from .google import GooglePlatform, GoogleWalletCustomEventTicket, GoogleWalletDefaultEventTicket
|
||||
|
||||
AVAILABLE_PLATFORMS = [ApplePlatform, GooglePlatform]
|
||||
|
||||
AVAILABLE_STYLES: dict[str, list[type[PassStyle]]] = {
|
||||
"apple": [AppleWalletEventTicket],
|
||||
"google": [GoogleWalletDefaultEventTicket],
|
||||
"google": [GoogleWalletDefaultEventTicket, GoogleWalletCustomEventTicket],
|
||||
}
|
||||
|
||||
AVAILABLE_STYLES_DICT = {
|
||||
|
||||
@@ -24,14 +24,18 @@ from walletobjects.constants import (
|
||||
from pretix.base.models import Event, OrderPosition
|
||||
from pretix.base.settings import GlobalSettingsObject
|
||||
from pretix.multidomain.urlreverse import eventreverse_absolute
|
||||
from pretix.plugins.wallet.i18n import localizable_to_dict
|
||||
from pretix.plugins.wallet.models import GoogleWalletInstance, GoogleWalletType
|
||||
from pretix.plugins.wallet.styles.base import (
|
||||
ColorSettingsField,
|
||||
FieldContentType,
|
||||
FieldGroup,
|
||||
FieldGroupDisplay,
|
||||
FloatSettingsField,
|
||||
ImageSettingsField,
|
||||
PassStyle,
|
||||
PlaceholderFieldEntry,
|
||||
PlaceholderFieldGroup,
|
||||
PredefinedFieldGroup,
|
||||
TextFieldGroup,
|
||||
WalletPlatform,
|
||||
@@ -102,30 +106,6 @@ class GooglePlatform(WalletPlatform):
|
||||
class GoogleWalletEventTicketStyle(PassStyle):
|
||||
platform = GooglePlatform
|
||||
|
||||
@property
|
||||
def settings(self):
|
||||
return [
|
||||
ImageSettingsField(
|
||||
identifier="logo",
|
||||
label=_("Logo"),
|
||||
default="pretixplugins/wallet/logo.png",
|
||||
),
|
||||
ImageSettingsField(
|
||||
identifier="hero",
|
||||
label=_("Hero Image"),
|
||||
default=self.event.settings.logo_image,
|
||||
),
|
||||
ColorSettingsField(
|
||||
identifier="bg_color",
|
||||
label=_("Background Color"),
|
||||
default=self.event.settings.primary_color,
|
||||
),
|
||||
FloatSettingsField(identifier="lat", label=_("Latitude"), min=-90, max=90),
|
||||
FloatSettingsField(
|
||||
identifier="long", label=_("Longitude"), min=-180, max=180
|
||||
),
|
||||
]
|
||||
|
||||
@cached_property
|
||||
def comms(self):
|
||||
return Comms(self.event.settings.get("wallet_google_credentials").read())
|
||||
@@ -144,57 +124,6 @@ class GoogleWalletEventTicketStyle(PassStyle):
|
||||
instance.save(update_fields=["data"])
|
||||
return result
|
||||
|
||||
def _generate_class(self):
|
||||
output_class = EventTicketClass(
|
||||
self.event.organizer.name,
|
||||
get_class_id(self.event, self.op),
|
||||
MultipleDevicesAndHoldersAllowedStatus.multipleHolders, # TODO: Make configurable
|
||||
self.event.name,
|
||||
ReviewStatus.underReview,
|
||||
self.event.settings.locale,
|
||||
)
|
||||
|
||||
output_class.homepage_uri(
|
||||
eventreverse_absolute(self.event, "presale:event.index"),
|
||||
get_translated_string("Website", self.event.settings.locale),
|
||||
get_translated_dict("Website", self.event.settings.locales),
|
||||
)
|
||||
|
||||
# TODO: callback url
|
||||
# output_class.callback_url(eventreverse_absolute(event.organizer,"plugins:wallet:google_webhook",))
|
||||
|
||||
if (lat := self.cleaned_settings["lat"]) and (
|
||||
long := self.cleaned_settings["long"]
|
||||
):
|
||||
output_class.locations(lat, long)
|
||||
elif self.event.geo_lat and self.event.geo_lon:
|
||||
output_class.locations(self.event.geo_lat, self.event.geo_lon)
|
||||
|
||||
output_class.country_code(self.event.settings.locale)
|
||||
|
||||
if hero := self.cleaned_settings["hero"]:
|
||||
output_class.hero_image(
|
||||
urljoin(eventreverse_absolute(self.event, "presale:event.index"), hero),
|
||||
self.event.name,
|
||||
)
|
||||
|
||||
if logo := self.cleaned_settings["logo"]:
|
||||
output_class.logo(
|
||||
urljoin(eventreverse_absolute(self.event, "presale:event.index"), logo),
|
||||
self.event.name,
|
||||
)
|
||||
|
||||
output_class.hex_background_color(self.cleaned_settings["bg_color"])
|
||||
output_class.confirmation_code_label(ConfirmationCode.orderNumber)
|
||||
|
||||
return output_class
|
||||
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = EventTicketObject(
|
||||
get_object_id(op), class_id, ObjectState.active, self.event.settings.locale
|
||||
)
|
||||
return output_object
|
||||
|
||||
def generate(self, op):
|
||||
self.op = op
|
||||
|
||||
@@ -223,18 +152,35 @@ class GoogleWalletEventTicketStyle(PassStyle):
|
||||
"https://pay.google.com/gp/v/save/%s" % generated_jwt,
|
||||
)
|
||||
|
||||
|
||||
class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
identifier = "event"
|
||||
name = "Event Ticket"
|
||||
@property
|
||||
def settings(self):
|
||||
return [
|
||||
ImageSettingsField(
|
||||
identifier="logo",
|
||||
label=_("Logo"),
|
||||
default=self.event.settings.logo_image
|
||||
or "pretixplugins/wallet/logo.png",
|
||||
),
|
||||
# TODO: wide logo
|
||||
ImageSettingsField(
|
||||
identifier="hero",
|
||||
label=_("Hero Image"),
|
||||
),
|
||||
ColorSettingsField(
|
||||
identifier="bg_color",
|
||||
label=_("Background Color"),
|
||||
default=self.event.settings.primary_color,
|
||||
),
|
||||
FloatSettingsField(identifier="lat", label=_("Latitude"), min=-90, max=90),
|
||||
FloatSettingsField(
|
||||
identifier="long", label=_("Longitude"), min=-180, max=180
|
||||
),
|
||||
]
|
||||
|
||||
@property
|
||||
def fieldgroups(self):
|
||||
def fieldgroups(self) -> list[FieldGroup]:
|
||||
return [
|
||||
PredefinedFieldGroup(identifier="venue", name=_("Venue")),
|
||||
PredefinedFieldGroup(identifier="date", name=_("Date")),
|
||||
PredefinedFieldGroup(identifier="seating", name=_("Seating")),
|
||||
PredefinedFieldGroup(identifier="ticket_holder", name=_("Ticket Holder")),
|
||||
TextFieldGroup(
|
||||
identifier="code",
|
||||
name=_("QR-Code"),
|
||||
@@ -281,81 +227,22 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
"direction": "column",
|
||||
"display": ["tight"],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "date",
|
||||
"sample": [
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(
|
||||
self.event.timezone
|
||||
),
|
||||
"SHORT_DATE_FORMAT",
|
||||
),
|
||||
"label": "Date",
|
||||
},
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(
|
||||
self.event.timezone
|
||||
),
|
||||
"TIME_FORMAT",
|
||||
),
|
||||
"label": "Time",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "seating",
|
||||
"sample": [
|
||||
{"content": _("Ground floor"), "label": _("Section")},
|
||||
{"content": "5 / 2", "label": _("Row") + " / " + _("Seat")},
|
||||
],
|
||||
},
|
||||
*self._preview_layout_front_card,
|
||||
{"fieldgroup": "code"},
|
||||
{"setting": "hero"},
|
||||
],
|
||||
},
|
||||
{
|
||||
"rows": [
|
||||
{
|
||||
"fieldgroup": "ticket_holder",
|
||||
"sample": [
|
||||
{"content": _("John Doe"), "label": _("Ticket Holder")},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "venue",
|
||||
"sample": [
|
||||
{"content": self.venue()[1], "label": self.venue()[0]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "date",
|
||||
"sample": [
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(
|
||||
self.event.timezone
|
||||
),
|
||||
"DATETIME_FORMAT",
|
||||
),
|
||||
"label": _("Event Start Time"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{"value": _("Sample product"), "label": _("Ticket Type")},
|
||||
{"value": "ABCDE-1", "label": _("Ticket Number")},
|
||||
{"value": "ABCDE", "label": _("Order Number")},
|
||||
{
|
||||
"value": eventreverse_absolute(
|
||||
self.event, "presale:event.index"
|
||||
),
|
||||
"label": _("Website"),
|
||||
},
|
||||
]
|
||||
},
|
||||
{"rows": [*self._preview_layout_back_details]},
|
||||
]
|
||||
|
||||
@property
|
||||
def _preview_layout_front_card(self):
|
||||
return []
|
||||
|
||||
@property
|
||||
def _preview_layout_back_details(self):
|
||||
return []
|
||||
|
||||
def venue(self):
|
||||
if self.event.location:
|
||||
name = {}
|
||||
@@ -374,10 +261,162 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
return "", ""
|
||||
|
||||
def _generate_class(self):
|
||||
output_class = super()._generate_class()
|
||||
output_class = EventTicketClass(
|
||||
self.event.organizer.name,
|
||||
get_class_id(self.event, self.op),
|
||||
MultipleDevicesAndHoldersAllowedStatus.multipleHolders, # TODO: Make configurable
|
||||
self.event.name,
|
||||
ReviewStatus.underReview,
|
||||
self.event.settings.locale,
|
||||
)
|
||||
|
||||
output_class.homepage_uri(
|
||||
eventreverse_absolute(self.event, "presale:event.index"),
|
||||
get_translated_string("Website", self.event.settings.locale),
|
||||
localizable_to_dict("Website", self.event.settings.locales),
|
||||
)
|
||||
|
||||
if (lat := self.cleaned_settings["lat"]) and (
|
||||
long := self.cleaned_settings["long"]
|
||||
):
|
||||
output_class.locations(lat, long)
|
||||
elif self.event.geo_lat and self.event.geo_lon:
|
||||
output_class.locations(self.event.geo_lat, self.event.geo_lon)
|
||||
|
||||
output_class.country_code(self.event.settings.locale)
|
||||
|
||||
if hero := self.cleaned_settings["hero"]:
|
||||
output_class.hero_image(
|
||||
urljoin(eventreverse_absolute(self.event, "presale:event.index"), hero),
|
||||
self.event.name,
|
||||
)
|
||||
|
||||
if logo := self.cleaned_settings["logo"]:
|
||||
output_class.logo(
|
||||
urljoin(eventreverse_absolute(self.event, "presale:event.index"), logo),
|
||||
self.event.name,
|
||||
)
|
||||
|
||||
output_class.hex_background_color(self.cleaned_settings["bg_color"])
|
||||
output_class.confirmation_code_label(ConfirmationCode.orderNumber)
|
||||
|
||||
if self.group_is_active("venue") and all(self.venue()):
|
||||
output_class.venue(*self.venue())
|
||||
|
||||
if SHIMMER:
|
||||
output_class.securityAnimation(AnimationType.FOIL_SHIMMER)
|
||||
|
||||
# TODO: callback url
|
||||
# output_class.callback_url(eventreverse_absolute(event.organizer,"plugins:wallet:google_webhook",))
|
||||
|
||||
return output_class
|
||||
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = EventTicketObject(
|
||||
get_object_id(op), class_id, ObjectState.active, self.event.settings.locale
|
||||
)
|
||||
fields = self.get_pass_fields(op)
|
||||
|
||||
if fields["code"]:
|
||||
output_object.barcode(
|
||||
Barcode.qrCode, fields["code"][0]["value"], fields["code"][0]["value"]
|
||||
)
|
||||
output_object.reservation_info(op.order.code)
|
||||
output_object.ticket_number(op.code)
|
||||
|
||||
output_object.valid_time_interval(op.valid_from, op.valid_until)
|
||||
output_object.ticket_type(
|
||||
get_translated_dict(
|
||||
str(op.item)
|
||||
+ (" – " + str(op.variation.value) if op.variation else ""),
|
||||
op.order.event.settings.get("locales"),
|
||||
)
|
||||
)
|
||||
return output_object
|
||||
|
||||
|
||||
class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
identifier = "event"
|
||||
name = "Default Event Ticket"
|
||||
|
||||
@property
|
||||
def fieldgroups(self):
|
||||
return [
|
||||
PredefinedFieldGroup(identifier="date", name=_("Date")),
|
||||
PredefinedFieldGroup(identifier="seating", name=_("Seating")),
|
||||
PredefinedFieldGroup(identifier="ticket_holder", name=_("Ticket Holder")),
|
||||
*super().fieldgroups,
|
||||
]
|
||||
|
||||
@property
|
||||
def _preview_layout_front_card(self):
|
||||
return [
|
||||
{
|
||||
"fieldgroup": "date",
|
||||
"sample": [
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(self.event.timezone),
|
||||
"SHORT_DATE_FORMAT",
|
||||
),
|
||||
"label": "Date",
|
||||
},
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(self.event.timezone),
|
||||
"TIME_FORMAT",
|
||||
),
|
||||
"label": "Time",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "seating",
|
||||
"sample": [
|
||||
{"content": _("Ground floor"), "label": _("Section")},
|
||||
{"content": "5 / 2", "label": _("Row") + " / " + _("Seat")},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@property
|
||||
def _preview_layout_back_details(self):
|
||||
return [
|
||||
{
|
||||
"fieldgroup": "ticket_holder",
|
||||
"sample": [
|
||||
{"content": _("John Doe"), "label": _("Ticket Holder")},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "venue",
|
||||
"sample": [
|
||||
{"content": self.venue()[1], "label": self.venue()[0]},
|
||||
],
|
||||
},
|
||||
{
|
||||
"fieldgroup": "date",
|
||||
"sample": [
|
||||
{
|
||||
"content": date_format(
|
||||
self.event.date_from.astimezone(self.event.timezone),
|
||||
"DATETIME_FORMAT",
|
||||
),
|
||||
"label": _("Event Start Time"),
|
||||
},
|
||||
],
|
||||
},
|
||||
{"value": _("Sample product"), "label": _("Ticket Type")},
|
||||
{"value": "ABCDE-1", "label": _("Ticket Number")},
|
||||
{"value": "ABCDE", "label": _("Order Number")},
|
||||
{
|
||||
"value": eventreverse_absolute(self.event, "presale:event.index"),
|
||||
"label": _("Website"),
|
||||
},
|
||||
]
|
||||
|
||||
def _generate_class(self):
|
||||
output_class = super()._generate_class()
|
||||
if self.group_is_active("date"):
|
||||
if self.event.date_from:
|
||||
output_class.start(self.event.date_from.isoformat())
|
||||
@@ -390,9 +429,6 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
DoorsOpen.doorsOpen, self.event.date_admission.isoformat()
|
||||
)
|
||||
|
||||
if SHIMMER:
|
||||
output_class.securityAnimation(AnimationType.FOIL_SHIMMER)
|
||||
print(output_class)
|
||||
return output_class
|
||||
|
||||
def ticket_holder_name(self, op):
|
||||
@@ -400,14 +436,6 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = super()._generate_object(op, class_id)
|
||||
fields = self.get_pass_fields(op)
|
||||
|
||||
if fields["code"]:
|
||||
output_object.barcode(
|
||||
Barcode.qrCode, fields["code"][0]["value"], fields["code"][0]["value"]
|
||||
)
|
||||
output_object.reservation_info(op.order.code)
|
||||
output_object.ticket_number(op.code)
|
||||
|
||||
if self.group_is_active("ticket_holder") and self.ticket_holder_name(op):
|
||||
output_object.ticket_holder_name(self.ticket_holder_name(op))
|
||||
@@ -426,16 +454,144 @@ class GoogleWalletDefaultEventTicket(GoogleWalletEventTicketStyle):
|
||||
elif seat.seat_number:
|
||||
output_object.seat(seat.seat_number)
|
||||
|
||||
output_object.valid_time_interval(op.valid_from, op.valid_until)
|
||||
output_object.ticket_type(
|
||||
get_translated_dict(
|
||||
str(op.item)
|
||||
+ (" – " + str(op.variation.value) if op.variation else ""),
|
||||
op.order.event.settings.get("locales"),
|
||||
)
|
||||
)
|
||||
|
||||
# places = settings.CURRENCY_PLACES.get(op.order.event.currency, 2)
|
||||
# output_object.face_value(int(op.price * 1000 ** places), op.order.event.currency)
|
||||
|
||||
return output_object
|
||||
|
||||
|
||||
class GoogleWalletCustomEventTicket(GoogleWalletEventTicketStyle):
|
||||
identifier = "event_custom"
|
||||
name = "Custom Event Ticket"
|
||||
|
||||
@property
|
||||
def _preview_layout_front_card(self):
|
||||
return [
|
||||
{
|
||||
"fieldgroup": "second_row",
|
||||
},
|
||||
{
|
||||
"fieldgroup": "third_row",
|
||||
},
|
||||
]
|
||||
|
||||
@property
|
||||
def _preview_layout_back_details(self):
|
||||
return [{"fieldgroup": "details", "direction": "column"}]
|
||||
|
||||
@property
|
||||
def fieldgroups(self):
|
||||
return [
|
||||
TextFieldGroup(
|
||||
identifier="second_row",
|
||||
name=_("Second Row"),
|
||||
max_entries=3,
|
||||
context_args={"order_position"},
|
||||
),
|
||||
TextFieldGroup(
|
||||
identifier="third_row",
|
||||
name=_("Third Row"),
|
||||
max_entries=3,
|
||||
context_args={"order_position"},
|
||||
),
|
||||
*super().fieldgroups,
|
||||
TextFieldGroup(
|
||||
identifier="details",
|
||||
name=_("Details"),
|
||||
max_entries=20,
|
||||
context_args={"order_position"},
|
||||
),
|
||||
]
|
||||
|
||||
def _generate_class(self):
|
||||
output_class = super()._generate_class()
|
||||
|
||||
output_class.setdefault("classTemplateInfo", {})
|
||||
output_class["classTemplateInfo"].setdefault("cardTemplateOverride", {})
|
||||
output_class["classTemplateInfo"]["cardTemplateOverride"] = {
|
||||
"cardRowTemplateInfos": [
|
||||
{
|
||||
"threeItems": {
|
||||
"startItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['second_row-0']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"middleItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['second_row-1']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"endItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['second_row-2']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
"threeItems": {
|
||||
"startItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['third_row-0']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"middleItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['third_row-1']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"endItem": {
|
||||
"firstValue": {
|
||||
"fields": [
|
||||
{
|
||||
"fieldPath": "object.textModulesData['third_row-2']"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
output_class["classTemplateInfo"].setdefault("detailsTemplateOverride", {})
|
||||
output_class["classTemplateInfo"]["detailsTemplateOverride"][
|
||||
"detailsItemInfo"
|
||||
] = []
|
||||
|
||||
return output_class
|
||||
|
||||
def _generate_object(self, op: OrderPosition, class_id: str):
|
||||
output_object = super()._generate_object(op, class_id)
|
||||
fields = self.get_pass_fields(op)
|
||||
|
||||
for row in ["second_row", "third_row"]:
|
||||
for i, field in enumerate(fields.get(row, [])):
|
||||
output_object.text_modules_data(
|
||||
f"{row}-{i}",
|
||||
localizable_to_dict(field["label"], self.event.settings.locales),
|
||||
localizable_to_dict(field["value"], self.event.settings.locales),
|
||||
)
|
||||
|
||||
return output_object
|
||||
Reference in new issue
Block a user