Skip to content

Add exchanging tickets to reusable media#78

Closed
robbi5 wants to merge 16 commits into
masterfrom
reusable-medium-exchange
Closed

Add exchanging tickets to reusable media#78
robbi5 wants to merge 16 commits into
masterfrom
reusable-medium-exchange

Conversation

@robbi5

@robbi5 robbi5 commented May 20, 2026

Copy link
Copy Markdown
Contributor

This requires pretix/pretix#6115

TODO:

@robbi5 robbi5 marked this pull request as ready for review May 28, 2026 10:14
val reusableMediaUsageEnforced = (settings?.json?.optBoolean("reusable_media_usage_enforced", false) == true)

val linkedReusableMedium = db.reusableMediumQueries.selectByLinkedOrderPosition(position.positionId)
.executeAsOneOrNull()?.toModel()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if this has multiple results?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could change it to a query that just counts, but do we want to check expired/active here too? Or more like: in which state is a ticket that already has a linked medium, but that medium is no longer active anymore?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could change it to a query that just counts, but do we want to check expired/active here too?

No, I think we don't need to check it here

Or more like: in which state is a ticket that already has a linked medium, but that medium is no longer active anymore?

For now, in an unusuable state, I guess, which is the safest option. We should figure that out once we have a real-world use case for ReusableMedium.expires, I really have no idea why it's in there. Maybe the idea was that e.g. a printed season ticket card should be re-printed every 5-10 years to get an updated photo instead of an old photo being carried around for decades? In that case the expiry should sync with the ticket expiry.

Comment thread libpretixsync/src/main/java/eu/pretix/libpretixsync/check/AsyncCheckProvider.kt Outdated
Comment thread libpretixsync/src/main/java/eu/pretix/libpretixsync/api/PretixApi.kt Outdated
Comment thread libpretixsync/src/main/java/eu/pretix/libpretixsync/check/AsyncCheckProvider.kt Outdated
val reusableMediaUsageEnforced = (settings?.json?.optBoolean("reusable_media_usage_enforced", false) == true)

val linkedReusableMedium = db.reusableMediumQueries.selectByLinkedOrderPosition(position.positionId)
.executeAsOneOrNull()?.toModel()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could change it to a query that just counts, but do we want to check expired/active here too?

No, I think we don't need to check it here

Or more like: in which state is a ticket that already has a linked medium, but that medium is no longer active anymore?

For now, in an unusuable state, I guess, which is the safest option. We should figure that out once we have a real-world use case for ReusableMedium.expires, I really have no idea why it's in there. Maybe the idea was that e.g. a printed season ticket card should be re-printed every 5-10 years to get an updated photo instead of an old photo being carried around for decades? In that case the expiry should sync with the ticket expiry.

Comment on lines +814 to +823
if (linkedReusableMedium == null) {
res.type = TicketCheckProvider.CheckResult.Type.EXCHANGE_REQUIRED
res.isCheckinAllowed = false
storeFailedCheckin(eventSlug, list.serverId, "exchange", position.secret!!, type, position = position.serverId, item = positionItem.serverId, variation = position.variationServerId, subevent = position.subEventServerId, nonce = nonce)
return res
} else if (reusableMediaUsageEnforced) {
res.type = TicketCheckProvider.CheckResult.Type.ALREADY_EXCHANGED
res.isCheckinAllowed = false
storeFailedCheckin(eventSlug, list.serverId, "already_exchanged", position.secret!!, type, position = position.serverId, item = positionItem.serverId, variation = position.variationServerId, subevent = position.subEventServerId, nonce = nonce)
return res

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a reason I don't yet understand, both of these cases trigger the error message reusable_media_exchange_not_implemented in my test, which is the wrong error message?

Comment thread libpretixsync/src/main/java/eu/pretix/libpretixsync/check/TicketCheckProvider.kt Outdated
if (!hasLinkedReusableMedium) {
res.type = TicketCheckProvider.CheckResult.Type.ERROR // EXCHANGE_REQUIRED, but not in offline mode
res.isCheckinAllowed = false
res.reasonExplanation = "This ticket needs to be exchanged, but this isn't possible while offline"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we translate that in the ui? → pretixSCAN

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants