verbb / events

Craft CMS Plugin for events management and ticketing.
Other
22 stars 13 forks source link

Programatically purchase a ticket for a user - documentation request #103

Closed anchovy closed 1 month ago

anchovy commented 2 years ago

What are you trying to do? We have events that will be 'free' for all registered users, so need to be able to programatically purchase a ticket when a user user indicates they want to attend the event, without forcing them to go into the commerce checkout flow - NB the ticket price for these users is $0.00.

What's your proposed solution? Documentation / examples of how to programatically purchase a $0.00 ticket for a registered user.

engram-design commented 2 years ago

So because ticket purchases are geared towards the Commerce cart experience, there's not an easy way of circumventing that. It'll require you to programatically create purchased tickets through a PHP module.

You can see how we handle this natively after an order is completed.

anchovy commented 2 years ago

Hi @engram-design.

I've managed to do this programmatically in a ajax(/sprig) template, but I'm getting unexpected results. I'm unsure if this is event or commerce related, so I've also added a bug on commerce

So - with the following code I'm getting hundreds of completed single line item orders, when I should just get one:

        {% set ticket = craft.events.tickets()
            .eventId(event.id)
            .typeId(getEventAccNoTicketId())
            .one() %}

        {% if ticket and ticket.purchasableId %}

            {# get the cart or create a new cart #}
            {% set cart = cart is not defined ? craft.commerce.carts.cart(true) : cart %}

            {# Generate the line item if it's not already in the cart #}
            {% set lineItem = craft.commerce.lineitems.resolveLineItem(cart.id, ticket.purchasableId) %}

            {# add the line item #}
            {% do cart.addLineItem(lineItem) %}

            {# Complete the order #}
            {% do cart.markAsComplete() %}

        {% endif %}

I'd expect to only have the one completed order, with the one line item.

NB - the CP goes away after a while as well and I get the install screen - I think whatever the bug is looping adding more orders and tying up all the DB connections/memory.

Secondary Issue When a purchased ticket/order is deleted the purchased tickets count on the event isn't updated.

  1. if I then go into the Event and look at the tickets - it's telling me, correctly (but incorrectly), that there's been 1000's of tickets purchased (should actually be only 5 of 6)
  2. go and delete all the orders so no tickets have been purchased,
  3. go back to the event, it's still saying it's got 100's of purchased tickets?

image

Seems like there's no event after deleting a order removing/updating the purchased ticket count/relationship?

engram-design commented 2 years ago

So do you actually want to create and complete an order for these programatically-created tickets? If so, that process does look right to me. How is this template loaded? Is it actually run multiple times?

I note you mention Sprig, and it's hard to say without looking at your full setup, but it's possible this template is being rendered infinitely if you're not careful. I'm no Sprig expert, but what little I did do I found myself in some of those situations.

If you took Sprig out of the equation and just added that code on a template route and ran the page, does that work?

anchovy commented 2 years ago

Hi @engram-design

Sorry for the delay in getting back to you on this one. We managed to get this to work by ensuring that cart is empty before adding the line item - this seems to stop it generating hundreds of line items, and therefore hundreds or pruchased tickets

        {% set ticket = craft.events.tickets()
            .eventId(event.id)
            .typeId(getEventAccNoTicketId())
            .one() %}

                {# get the cart or create a new cart #}
                {% set cart = cart is not defined ? craft.commerce.carts.cart(true) : cart %}

                {# Remove any exiting line items #}
                {% do cart.setLineItems([]) %}

                {# Generate the line item #}
                {% set lineItem = craft.commerce.lineitems.resolveLineItem(cart.id, ticket.purchasableId) %}

                {# add the line item #}
                {% do cart.addLineItem(lineItem) %}

                {# Complete the order #}
                {% do cart.markAsComplete() %}

        {% endif %}

Issue we have now is if we go and delete this order from commerce, the event is still listing the ticket as sold, and the query for purchased tickets is returning the ticket, even though the commerce order has been deleted?

        {% set purchasedTicketsQuery = craft.events.purchasedTickets()
        .eventId(event.id)
        .customer(craft.commerce.getCarts().getCart().customer)
        .ticketTypeId(getEventAccNoTicketId())
        .one() 
        %}

I'd have expected that once the commerce order was deleted, the associated ticket in the event would be deleted as well, or is this not the case?

anchovy commented 2 years ago

p.s. the 'deleted' ticket in the order view:

image
engram-design commented 1 month ago

I've just realised I never responded to this, sorry! Closing for now, but happy to reopen.