38 replies [Last post]
ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Was this information Helpful?

Ok, I've not been using UC and Drupal too long, but I just set up an online ticket sales system and thought I'd share a rough outline about how I did this - I'm going to try and flesh this out over the next few weeks as time permits - this is just a start, and hopefully I've not missed anything. There may be better ways to do this - I can't claim this way is the best or only and suggestions are of course welcome.

We had a requirement to sell carnival ride tickets online, where each ticket needed to be unique (so it could only be used once). Each box office where the tickets could be exchanged for wristbands would be equipped with a small PC running Ubuntu with a monitor and hand scanner and connected via a wireless network. Some simple custom code (not drupal based, though it could have been) to do ticket validation would be accessed via a web page.

When the ticket was presented, the bar code on the ticket would be scanned, this would be checked against the database - if the ticket was valid and had not previously been used, a large green check-mark would appear on the display. If the ticket was not valid a large stop sign would be presented along with the reason for validation failure. As soon as a valid ticket is scanned, the database is updated with the time the ticket was used.

Modules you will need:

CCK
Barcode
Date
Print
Token
Ubercart (of course)
uc_node_checkout
uc_restrict_qty
Views

There are probably a few dependencies I've missed, so be sure to check what each module requires.

Start by creating your event ticket, following the instructions for using uc_node_checkout here: http://drupaleasy.com/blogs/ultimike/2009/03/event-registration-ubercart Modify the names as needed so it reflects a ticket rather than an event.

There's no need for a Body field; the Title field I changed to "Issued to" and the publishing status of "not published" (I didn't want people trolling for tickets). In addition to the Status and Order Id fields, I created a Barcode field and a UsedOn field (a datetime field). The default value of the barcode field is used to indicate the length of the barcode. All of these fields are set to be restricted via the node checkout settings. So when the ticket product is added to the cart, the only thing asked for is the "Issued to" field (this can be handy if you want to require positive identification for the tickets).

The product attributes were also set to restrict the product quantity in the cart. By doing this, we prevent someone from putting a single product ticket in the cart and then changing the quantity at checkout/cart review - since uc_node_checkout puts each product in the cart with unique attributes, this does not prevent someone from purchasing multiple individual tickets.

I also modified the node checkout settings admin/store/settings/node-checkout/settings to use "Ticket" in the "Order Product Attribute" and just the "[nid]" in the order product options - just using the "[nid]" in the option product settings is needed for the email and ticket link generation. If you need more than the nid you will need to modify the ubercart template code (below) to account for this.

Also a small modification to modules/barcode/barcode.module to comment out the call to drupal_set_message(), since this information doesn't really need to be shown to the customer.

The custom PHP code used when the order checkout is complete was modified from the above uc_node_checkout example to create the actual barcode - as I wanted the barcode to be unguessable (to help prevent fraud) I used a random string generator from: http://php.net/manual/en/function.rand.php - and to help keep things unique in the database (not that the random string shouldn't do that already), the barcode is appended with the 6 digit nid that was created by uc_node_checkout.

if (isset($order)) {
  foreach ($order->products as $product) {
    if (isset($product->data['node_checkout_nid'])) {
      $node = node_load($product->data['node_checkout_nid']);
      $node->field_tckt_status['0']['value'] = 1;
      $node->field_tckt_orderid['0']['value'] = $order->order_id;
      $tcktLength = max( $node->field_tckt_barcode['0']['barcode'], 7 ) - 6;
      $node->field_tckt_barcode['0']['barcode'] = genRandStr($tcktLength,$tcktLength)
       . sprintf('%06d', $product->data['node_checkout_nid'] );
      node_save($node);
    }
  }
}

For the customer printing of the barcode, a node view called "ticket" was created taking an argument of the nid and displaying the Title field and the barcode field. The view filter was set to "published or admin" again to prevent trolling for tickets - since each customer is required to create an account at checkout, and uc_node_checkout updates the created node to reflect the actual owner, this allows only the person who purchased the ticket to access/print it.

Since printing access to the ticket is via the view, the print module was configured to show "ticket/*" in System/Non-content pages. Some custom CSS was also created for the print module so that the ticket didn't have all the extra stuff that the print module usually inserts by default.

Once the order checkout is complete, the customer receives a copy of the invoice via email, and within the invoice is a link to each ticket for printing - the links take the form of:

http://www.website.com/print/ticket/nid

and are inserted into the email via a modified ubercart template in ubercart/uc_order/templates - basically I started with a copy of customer.itpl.php as ticket.itpl.php - if you search for SKU: within the template, you'll find where the attribute information is inserted in to the email, which I modified to look like:

// Code modified to support ticket printing
if( strpos( $product->model, 'tckt' ) !== FALSE ) {
  if (is_array($product->data['attributes']) && count($product->data['attributes']) > 0) {
    foreach ($product->data['attributes'] as $attribute => $option) {
      echo '<li>'. t('<a href="@ticket-link" target="_blank">Click here</a> to access your ticket for printing (you must
be logged in to the <a href="@web-site" target="_blank">Parker Days web site</a>).', array('@ticket-link' => url('print/ticket/'.$option), '@web-site' => url('user'))) .'</li>';
    }
  }
}
else {
  if (is_array($product->data['attributes']) && count($product->data['attributes']) > 0) {
    foreach ($product->data['attributes'] as $attribute => $option) {
      echo '<li>'. t('@attribute: @options', array('@attribute' => $attribute, '@options' => implode(', ', (array)$option))) .'</li>';
    }
  }
}

To use the new template, the ubercart conditional action for sending the order must be modified at: admin/store/ca/uc_checkout_customer_notification/edit/actions and specify the template to be the ticket template. Likewise if you want your customer to be able to access their ticket link when the view the order online, you can set the template in admin/store/settings/orders/edit/basic to be your new template - this way if they click on the "view a printable version of the order" they'll be able to see the link(s).

As I mentioned earlier, I've got the validation code all working and I'll try to get that pulled together for posting in the next few days.

This work probably should be implemented as some sort of module, but I'm not quite far along enough with drupal to tackle writing a module quite yet.

--Scott

Cayenne's picture
Offline
Joined: 12/31/2008
Juice: 620
Wow Scott! You've done what

Wow Scott!

You've done what I had only dreamed about. Major kudos! I am running an event site and have wanted to add something like this.

Couple of things... Do you think that creating a node for each ticket sold will unduly clog up your database? Or do you plan to do periodic housecleaning?

What are you using for your scanning/validation function?

Finally, you may find my uc_who_bought_what module to be of use for creating lists of ticket holders.

Michael

ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Thanks. The way I figured it

Thanks.

The way I figured it was there's going to be database overhead no matter what I did; I'm not overjoyed by cluttering up the tables with nodes and CCK entries just related to tickets, but... As our event is only once a year, my plan is to simply clean out the unpublished nodes at the end of the event - for people that have multiple concurrent events, some finer granularity is certainly needed - one option might be to create an additional field in the ticket profile that is used to store an event code (such as the product SKU), which you could then use to identify the nodes you want to remove at the close of the event. I'm also going to look at indexing the barcode in the content_type_xxx table.

The scanning validation is done using a hand scanner and a web page with some back end PHP code. There's a single input field on the web page that the ticket number gets entered in to (the scanner looks like a keyboard entry device to the PC). Once the ticket number has been entered, an AJAX query is made to the PHP back end which looks up the ticket in the content_type_xxx table and sends back an XML formatted status. There are 2 DIV's (with style="display:hidden") on the page that each contain an image - one a stop sign, the other an OK check-mark. The javascript that processes the status response simply sets the display style of the appropriate DIV to 'inline', the ticket field is reset and is ready for the next scan. Since the checking is all done via AJAX there are no unnecessary page loads for each ticket scan. I'm still cleaning up the code, but as soon as it's cleaned up I'll post it so people can use it as a base for building their own validation method.

I have been looking at uc_who_bought_what and will likely use it to help service patrons with lost or forgotten tickets - of course if the ticket gets lost and someone else uses it, they are SOL. Thanks for the suggestion.

--Scott

Cayenne's picture
Offline
Joined: 12/31/2008
Juice: 620
Re: Thanks. The way I figured it

Okay, that's pretty good.

Hmmm. Maybe the more elegant (and harder to make) solution would be to render the invoice on-the-fly into a ticket (maybe using calls to the hooks in the modules you used, and have a single database table that connects uc_order_product to whether it has been scanned or not (and maybe when and by whom!)

But still, this be way cool!

ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Re: Re: Thanks. The way I figured it

When you create your ticket profile for uc_node_checkout, CCK (?) creates a new table that contains just the additional field information, each row in the table represents a unique ticket. In my case the table is called content_type_carnival_ticket_profile and contains a

  • vid
  • nid
  • field_tckt_status_value
  • field_tckt_orderid_value
  • field_ticket_barcode_barcode
  • field_tckt_barcode_title
  • field_tckt_used_value

This is the table that gets looked at by the validation code, and if it finds the ticket, then the field_tckt_used_value gets a date stamp put in it:
UPDATE `content_type_carnival_ticket_profile` SET `field_tckt_used_value` = now() WHERE `nid` = $nid LIMIT 1;

I agree that having the invoice actually have the tickets on it would be nice rather than having links to the printable version of the tickets - I just couldn't find a good way to make this happen in the first pass - still researching though.

Cayenne's picture
Offline
Joined: 12/31/2008
Juice: 620
Re: Re: Re: Thanks. The way I figured it

I need to develop a little hook to extract data from the attributes of an order and do useful things with the data, so maybe that will be of assistance...

blasthaus's picture
Offline
Joined: 01/10/2010
Juice: 17
barcode scanner

wow thanks so much for posting this. i've been working on something like this for awhile now on a non-drupal site just using paypal IPN and php, but this site will be drupalized soon so this is very helpful. please do tell more about the specific barcode scanner you are using and your php interface scripts, that would be of huge help as i know nothing about the retrieval part of this. for example is it possible to have a wireless scanner without having to look at a PC screen after each ajax response? i should think its just a matter of interfacing with the tones/UI of the scanning device.
thx again for this!
also if someone lets say bought 4 tickets, would you print 4 separate tickets or just have one ticket represent 4 units?
-wil

ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Ticket Check Code

My apologies for the delay in posting things - got caught up in planning the event.

I've attached the code for doing the check - it's not fully finished; for example, I want to have a login function (the current login/use validation code is very primitive) and some additional error handling, but it's enough to get someone who can code in PHP and Javascript going.

What's in the zip?

  • yes.gif, no.gif - what gets shown on the display depending on whether the ticket is valid or not - images from Wikipedia
  • ajax-loader.gif - animated "working" from www.ajaxload.info
  • index.php - well, the main web page
  • xml.class.js - simple XML support on the client side
  • xml.class.php - simple XML support on the server side
  • webtoolkit.md5.js - creates MD5 hashes for Javascript
  • mysql4.php - some classes to help with mysql
  • db_connect.php - the database connection info
  • ticket.class.php - some support PHP - this is where the ticket specific lookup info is kept
  • check.php - the PHP that gets launched by the AJAX request to check the ticket

So, what you need to do to make this work for your environment is primarily to modify ticket.class.php to reflect your actual table layout where the ticket information is stored. Since this depends on how you create your ticket profile via CCK, it will be unique to your requirements.

When you browse to the index.php all you are really going to see is the field to enter the ticket # - this code looks for a 16 character ticket, but times out and sends whatever it has if more than 2 seconds elapse between characters entered. All of the images are loaded when the page initially loads and then the javascript enables the display of the appropriate image depending on what's going on - when the ticket barcode is sent, the "loading" image is enabled - when the response comes back, that image is disabled and then the "yes" or "no" is enabled and a status message is presented.

Ideally this would be a module that plugs in to drupal, and now that I understand more about module creation, I may eventually create one out of this code. The module could even create the initial content type for you, which would probably help a lot of folks out in using it.

@blasthaus - the scanners I'm currently using are made by Symbol - nice, but pricey at $150+ each. I'm going to be evaluating an Adesso scanner shortly which is in the $60 range. I've not looked at any wireless scanner options since I was using what I had on hand and I have a budget of $0 - it looks like Unitech makes a reasonable one in the under $500 price range - though it would take some additional programming to use it.

As far as the multiple tickets go - if the customer purchased 4, they would print out 4 separate tickets - each with unique barcodes. Admittedly this is a bit more hassle for the customer, since they have to put 4 individual tickets in the shopping cart. I did consider allowing one barcode to represent multiple tickets and it could be easily done with the existing code (probably by having the checkout completion code pick up the Qty info from UC and stuff it into an additional field in the ticket profile node), but I didn't want to get in to the potential customer service hassle - people are generally used to "one ticket - one person."

--Scott

AttachmentSize
ticket-check.zip 33 KB
blasthaus's picture
Offline
Joined: 01/10/2010
Juice: 17
you rock

Seriously this is awesome work. Can't wait to take a look at the zip. My thoughts are that if you were to make a module with a content type the response would be huge especially if the entire solution down to the basics of managing the scanning part were laid out for noobs. It's very possible that other modules could be brought in to the mix or developed in order to extend the event management aspects as well, ie finals reporting, auto-emailing of ticket-counts, frequent buyer programs, back-up ticketholder print-outs, etc. There are a lot of expensive ticketing services which handle all of this kind of thing and charge a high service charge to the end-customer. (off topic news: Ticketmaster is now trying to merge with Clear Channel if you can imagine what that means). So rolling your own ticketing solution with Drupal and Ubercart is a big step forward.

One side note, I do think the option of a "group ticket" would be a good idea to enable, maybe just in a CCK field or it could just be implemented i presume on the front end with options from the attributes module. Group tickets would speed up the entry process in larger events and be of use for discounts as well as certain ticket types like in travel and tourism industry (group tours etc.).

I may as well throw one more thing out while I'm at it which is the idea of a customer option to send QR barcodes via email that they can save on their cellphones. this is the future of barcode ticketing and among other things makes it easier for customers who buy for others to give them their ticket.

-wil

ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Re: you rock

A couple of additional items that I've found as I'm doing some more testing today.

You should consider setting the view filter to also only allow viewing when the 'content: Status = 1' of the node (in addition to the 'Node: Published or admin' filter outlined earlier. Since the ticket profile node gets created as soon as the item is put in the cart, people may try to get clever if they realize the ticket # in the cart is the nid - now, normally this wouldn't be an issue, since the actual barcode isn't generated until checkout is complete - so all they would see is the default value of the barcode - but you might as well avoid any possible confusion.

Also, for scanners using the javascript I provided - the scanner needs to be set to not send a termination character (like a CR/LF or LF) - I've not seen a scanner yet that didn't allow this to be programmed, but you may have to go to the scanner web site to download the full programming guide. Also you may need to adjust the barcode height and scale to work with your particular scanner - the new Adesso scanner I got needs a scale of 1.0 in order to keep the 16 digit EAN 128 completely within its viewing range. The Symbol scanners I have have a much wider view range (different technology), so they work fine with the 30/2.0 settings for Barcode.

Also, be aware that Barcode checks in /sites/default/files/barcode for a PNG that matches the code; if it finds the file it uses it, if it doesn't a new file is generated - so if you need to regenerate codes after changing the scale/height, delete all the PNG files in that directory.

--Scott

Francisco Luz's picture
Offline
Joined: 06/23/2010
Juice: 13
No need for uc_node_checkout

Just an idea related to the database overhead, wouldn't it work if you create a new content type, say called "tickets", add some cck fields (to hold the barcode string for instance) then turn this new content type into a product type at ../admin/store/products/classes .
Once you have done that you won't need the node check out module anymore and you can add new tickets (products) just like any other uc product.

Francisco Luz's picture
Offline
Joined: 06/23/2010
Juice: 13
Re: No need for uc_node_checkout

Also, to keep the barcode unique for each order you could use either hook_uc_payment_entered (http://api.ubercart.org/api/function/hook_uc_payment_entered/2) or hook_ca_predicate (http://api.ubercart.org/api/function/uc_flatrate_ca_predicate/2/references) to generate an unique barcode string and save it into a table you had previously created.

marthaeasypics's picture
Offline
Joined: 01/04/2010
Juice: 2
Thanks Scott

Thank you so much Scott for your brilliant, step-by-step tutorial. It would help us noobs a lot. Smiling

kurokikaze's picture
Offline
Joined: 12/14/2009
Juice: 24
Awesome tutorial

Thanks, this is really awesome and useful tutorial.

nulimitz's picture
Offline
Joined: 06/09/2010
Juice: 3
Great Tutorial

This is a great tutorial. I thankful you took the time to explain in detail how to set it up. I am still working on getting this setup so it works. I keep running into configuration errors on my part. I want to hammer this out because it is a feature that could be useful for my site and a friends site as well. Thanks again.

ScottW's picture
Offline
Joined: 12/31/2009
Juice: 16
Some lessons learned

Well, the event has come and gone, so I thought I'd update this with a few lessons learned.

For the barcode field, I ended up increasing the "number of values" for the field to 10, which with the appropriate code modifications allows people to add up to 10 tickets at one time under the same name to the cart.

Now, for the problems - it appears that a number of folks who purchased, did not immediately follow the link in their email to print the tickets - instead they waited until the day of the event. This would have been ok, except the web site server was not appropriately tuned (mainly MySQL and kernel) to handle the level of traffic - so frustration when people couldn't print tix, etc. We had to implement a backup plan where people who brought in the printed email invoice could be issued replacement tix.

Lesson learned: Send the tix to the customer as a PDF attached to the email (the way Disney does). I've not looked in to how to do this yet.

A review of all the printed tix after the event showed there's a huge difference in how certain browsers print certain things. I had tried printing under both Firefox and IE and the tix looked pretty good, but there's another browser out there (I suspect Safari based on the percentage of tix) that was printing the bar codes so small that they had trouble being read. In addition, general print quality was an issue in a few cases - printers with clogged print heads or that were low on ink in a handful of cases made the barcodes unreadable (even though the barcodes were on the page 3 times - something I learned from Disney) - and coupled with the barcodes being smaller than normal, you would have needed a magnifying glass to manually enter the numbers (assuming you had this as a backup process for the ticket validate, which we did not).

Lesson learned: The barcode size might be resolved by sending everything in a PDF. This is the way Disney does it and I suspect that Adobe does a better job of printing exactly what the PDF has regardless of platform (that's part of it's job after all). After the fact I noted that in addition to putting the barcode on the page multiple times, Disney also puts the code on vertically as well as horizontally - this, I suspect is done to help with issues like head clogs. When possible, look at what the "big boys" do, and learn.

There was one instance that a customer thought by printing only the first page of an order, they had all 3 tix (because the barcode appeared 3 times on the page).

Lesson learned: Ya got me... It was clearly stated in the email that you should print all pages (one ticket per page). Maybe an enhancement to the validation to say that there were multiple tix associated with the order and an option for the person doing the validation to "accept" all/part of them.

In general, internet access from the ticket booths was an issue and we had problems being able to validate tix, so we had to take the approach that if it couldn't be validated, it was probably ok (be aware - the code I shared for validation is not at all robust in dealing with unreliable internet access)

Lesson learned: Work on reliable internet from the ticket booths. The barcode aspect alone seemed to keep people honest, coupled with the fact that IMO people usually are honest. In the post event review, no duplicate tix were found.

--Scott

nam_sandstorm's picture
Offline
Joined: 07/19/2010
Juice: 7
Seat Booking

Hi,

Is there a way that I can have an event where people book seats by selecting them? I am considering using UC for a theatre where people would need to select the seat(s) they want to buy tickets for.

Francisco Luz's picture
Offline
Joined: 06/23/2010
Juice: 13
Slicky Seat Selection Form

@nam_sandstorm,

Surely there is, I would use ajax and jquery libraries. I haven't tried any of the suggestions below, but here is some stuff that might help you set your foot on the road.

1. http://ww.digital-web.com/articles/jquery_crash_course (this is a very nice reading about jquery + it shows how to build an airplane seat plan for dynamic selection, here is the demo result http://www.digital-web.com/extras/jquery_crash_course)
2. http://plugins.jquery.com/project/snakecharmer (this is another jquery project that you should consider implementing, I have only read it's description and to me it sounds like just about what you need)
3. http://drupal.org/project/ajax (this drupal module could do all the heavy lifting when it comes to connecting the dots)
4. http://drupal.org/node/348475 (if you are not familiar with ahah in drupal still, you should read this article then)

Hope it helps,

http://francisco-luz.blogspot.com

nam_sandstorm's picture
Offline
Joined: 07/19/2010
Juice: 7
Slicky Seat Selection Form

@Francisco Luz

Thank Francisco ... unfortunately it pushes my skills requirements and time further than I hoped. As soon as I have more time I will look into it.

Francisco Luz's picture
Offline
Joined: 06/23/2010
Juice: 13
No probs mate, This guy here

No probs mate,
This guy here http://rowlandsgroup.com is building a coach booking system for my website http://www.outbackbrazil.com that uses similar technique illustrated in those links I've sent above. You could contact him him for a quote if you like.

edygorbacev's picture
Offline
Joined: 08/02/2010
Juice: 3
i should try this tutorial

nice.. il try it.. Smiling.. im stuck with my own work. kind of crazy here becouse its always show me false output. Hope this will help my project..

khan1294's picture
Offline
Joined: 08/15/2010
Juice: 5
EventStorm: Event Ticketing, Registration, Marketing, all in one

If you want to host and promote a successful event today, there are some minor and not-so-minor challenges you could potentially face. How do you get the word out? How do you handle invitations, registration, and payment processing? How do you market it? How do you organize and manage it? Most often you need different applications and services to support all of these functions, and we at Eventstorm would like to change that idea.
With you in mind, we’ve worked hard to design a service to help you with your everyday tasks as an event marketer – a service that will make your life easier while increasing your ticket sales and event attendance.

It’s time to upgrade your events. Imagine a service that takes all of the features you need to launch an event into one easy-to-use application. Imagine a dashboard with full visibility over all event ticketing, event registration, and marketing data of your business. Imagine never having to move your precious contacts between different websites and services. Imagine sending invitations, custom reminders, follow-up emails, and even text messages all from one location as soon as you create an event. Imagine never having to re-create an event in Facebook again.

Let Eventstorm show you how we are going to make your life easier and your events more successful. EventStorm strives to upgrade your events with a robust and intuitive promotion platform that handles all aspects of an event, from registration and ticketing to marketing and accounting. Users of the service can build custom-tailored event pages, create invitations, send custom newsletter emails, send text messages, manage payments, and even link out to many social networking and bookmarking sites to spread the word. Successful events, now all managed from one application: http://www.eventstorm.com

arvana's picture
Offline
Joined: 12/17/2010
Juice: 26
Send PDF ticket as email attachment

As suggested by ScottW I decided to implement this ticket system and send the barcoded ticket as a PDF attachment upon order completion. It turned out to be a bit of a headache, but I eventually got it to work. Here's how to do it.

  1. Patch mimemail module: http://drupal.org/node/932962 (if patch hasn't been committed) and install.
  2. Patch print module: http://drupal.org/node/1044138 (if patch hasn't been committed) and install. You will also need a PDF converter, as described in the module installation instructions; I used dompdf.
  3. For my purposes, I included a number of extra fields in my ticket content-type: username, order number, check-in time, and notes. The last two are for the purposes of admission at the gate.
  4. Create a 'ticket' view that includes multiple instances of the barcode (I included 3 barcode images and one barcode text field). I've attached mine for reference.
  5. Create print_pdf.tpl.php and print-pdf.css files to format your PDF and insert them in your theme folder. I've attached mine for reference.
  6. Change the Conditional Action shown in ScottW's original post to the code shown below:
if (isset($order)) {
  module_load_include('inc', 'print_pdf', 'print_pdf.pages');  // require print_pdf.pages.inc

  // set up email to send ticket
  $recipients[] = $order->primary_email; 
  $subject = "Your ticket is attached";
  $body = '<p>Your ticket is attached.&nbsp; Please print it now and keep it in a safe location.&nbsp; If necessary, you can also re-download it at the following link.</p><ul>';
  $attachments = array();

  // check for tickets in the order
  $counter = 0;
  foreach ($order->products as $product) {
    if (isset($product->data['node_checkout_nid'])) {  // product is a ticket

      //  update ticket node
      $node = node_load($product->data['node_checkout_nid']);
      $node->field_orderid['0']['value'] = $order->order_id;
      $node->field_user['0']['value'] = $account->name;
      if (strlen($node->field_barcode['0']['barcode']) < 18) {
        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890';
        $string = $chars{rand(0, 61)};
        for ($i = 1; $i < 12; $i++)
        {
          $string .= $chars{rand(0, 61)};
        }
        $node->field_barcode['0']['barcode'] = $string . sprintf('%06d', $product->data['node_checkout_nid'] );
      }
      node_save($node);

      //  add ticket to email
      $path = 'ticket/' . $node->nid;
      $attachments[$counter] = array(   // attach ticket
        'contents' => print_pdf_controller($path),
        'filemime' => 'application/pdf',
        'filename' => 'ticket-' . $order->order_id . '.pdf',
      );
      $link = 'http://zoxon.com/printpdf/ticket/' . $node->nid;
      $body .= '<li><a href="'. $link . '">' . $link . '</a></li>';

      $counter++;
    }
  }

  // finish the email
  $body .= '</ul><p><br />Upon arrival at the event, you will need to present your ticket and matching photo ID for admission.</p><p>Please also review the attached Terms and Conditions carefully so that you know what is expected of you.</p><p>Thank you, and see you there!</p>';

  // add the Terms & Conditions as an attachment
  $attachments[$counter] = array(
    'filepath' => '/sites/default/files/Terms-Conditions.pdf',
    'filemime' => 'application/pdf',
   );

  // send the email
  mimemail( $settings['from'], $recipients, $subject, $body, FALSE, array(), drupal_html_to_text(decode_entities($body)), $attachments );
}

Note that this code also attaches a static file, Terms-Conditions.pdf, which you may not want to do, but I left the code there in case you want to know how to do it. Also, this code checks to see if the barcode has already been set, just in case this Conditional Action accidentally gets triggered a second time; we wouldn't want to reset someone's barcode after they have already received their ticket. This means that when you create the barcode field, the default value has to be shorter than (in my case) 18 digits (or NULL).

AttachmentSize
import-ticket-view.txt 9.03 KB
print_pdf.tpl_.php_.txt 1.1 KB
print-pdf.css_.txt 1.34 KB
secondglance's picture
Offline
Joined: 11/10/2009
Juice: 38
r u kidding me

your a mad dog Arvana...

this is unbelievable. have you got a example PDF we could take a look at?? I have a lil project that's gonna love this.... $$$

did the barcode read better?? good work.

DamienMcKenna's picture
Offline
Joined: 11/12/2008
Juice: 18
Some updates

I've been trying to get this working correctly, and I've finally pieced it together. Here's what I'm using:

  • Drupal v6.24
  • MIMEmail v6.x-1.0
  • Print v6.x-1.14
  • tcpdf v5.9.149
  • fpdi v1.4.2

The key part is that the MimeMail module's data structures are different to what is listed above, so I had to change the code to match the following:

<?php
      $attachments
[$counter] = array(   // attach ticket
       
'filecontent' => print_pdf_controller($path),
       
'filemime' => 'application/pdf',
       
'filename' => 'ticket-' . $order->order_id . '.pdf',
       
'filepath' => '',
      );
?>

The key change is using 'filecontent' instead of 'contents', and the empty 'filepath' is looked for in mimemail_html_body() in mimemail.inc.

geetwo's picture
Offline
Joined: 06/10/2011
Juice: 5
Re: Selling Tickets

Hi everyone, i had been looking for this solution till one day a came here and got your ideas.
Such a wonderful post... thanks for making my spent night worth. but the thing is i cant get it to work properly after a few days. maybe cose im not an expert but manage out to be a good student. my request is to maybe have a folder with everything ste up cos there are thing listed below, i cant understand:

1 - patch the modules
2 - configure the print module properly
2- locate the proper theme folder to upload the scripts given by Arvana
4- find the right code to replace on the ticket.itpl.php file...

I know this can be such a biring thing to do, but i've suffered enough till i met drupal and, just to get this solution...

we dont have a similar solution in my country and it woul be a nice thesis for my school final task

best regards and hope to hear from you guys soon.

Guert - mozambique

arvana's picture
Offline
Joined: 12/17/2010
Juice: 26
Re: Re: Selling Tickets

Hi geetwo, it has been a while since I made that post, and all of the modules have incorporated those patches into their current versions. However it is still a very complicated setup to get working properly and I really don't recommend it to anyone who is not reasonably expert in Drupal.

I'm sorry, I know that isn't very helpful, but this is really pushing the limits of the technology and it's not something that you are likely to be able to get working without digging into the code and understanding it thoroughly.

Having said that, here are answers to your questions:

1. Already done, just install the latest version of those modules
2. As far as I remember there is nothing special about configuring Print other than making sure your PDF converter is working.
3. The theme files go into the main folder of your current theme.
4. The ticket is created with the ticket View which is then passed through Print_PDF. The formatting of the PDF content is adjusted by editing print_pdf.tpl.php and print_pdf.css which are also affected by the ability of the PDF converter to interpret CSS; in my case I found that dompdf was the best for my needs.

geetwo's picture
Offline
Joined: 06/10/2011
Juice: 5
arvana wrote: Hi geetwo, it
arvana wrote:

Hi geetwo, it has been a while since I made that post, and all of the modules have incorporated those patches into their current versions. However it is still a very complicated setup to get working properly and I really don't recommend it to anyone who is not reasonably expert in Drupal.

I'm sorry, I know that isn't very helpful, but this is really pushing the limits of the technology and it's not something that you are likely to be able to get working without digging into the code and understanding it thoroughly.

Having said that, here are answers to your questions:

1. Already done, just install the latest version of those modules
2. As far as I remember there is nothing special about configuring Print other than making sure your PDF converter is working.
3. The theme files go into the main folder of your current theme.
4. The ticket is created with the ticket View which is then passed through Print_PDF. The formatting of the PDF content is adjusted by editing print_pdf.tpl.php and print_pdf.css which are also affected by the ability of the PDF converter to interpret CSS; in my case I found that dompdf was the best for my needs.

many thanks i've worked more on the project and i can now send the ticket attached, just still need to correct some few problems... Thank you fore your rapid response...

Regards

arvana's picture
Offline
Joined: 12/17/2010
Juice: 26
Re: arvana wrote: Hi geetwo, it

That is awesome -- can you report back on what you did to configure everything, to make it easier for others?

simonswiss's picture
Offline
Joined: 09/01/2009
Juice: 31
d7?

Any idea if such a setup would be feasable in drupal 7? Seems like a bunch of the modules haven't been ported yet.

Actually i don't need the barcode and some other stuff, what i really need is to be able to send the tickets via PDF of share a download link with the users once the payment is completed..

Jeno's picture
Offline
Joined: 07/21/2011
Juice: 11
Agreed !

Hi,

Is there an idiot-proof version of the tutorial?
Appreciated if some one can write up something for an absolute beginner.

Thanks

sideswitch's picture
Offline
Joined: 02/01/2010
Juice: 22
Export Features and Upload to GitHub

Hi there.

It would be SUPERB if you were to export what you've done to Features, and share it with us on Drupal.org or GitHub?

Taesto's picture
Offline
Joined: 11/02/2011
Juice: 3
It works so far!

Hi everyone,

Just wanted to say thanks for the tutorials. So far I've just done the part where the pdf ticket is sent automatically, with a barcode generated on-the-fly.

Just read carefully the first post of scottw and used the php code of arvana

I had a little trouble understanding how the barcode module works, and find a free barcode font, and set the barcode module to the corresponding font encoding.

Other than that, took me one morning to do it.

And I don't consider myself a drupal expert at all.

I haven't yet tried to print the barcodes and validate them. I was just looking for the professional look of a barcode-enabled ticket.

grachan2's picture
Offline
Joined: 11/10/2011
Juice: 3
Re: Selling Tickets

I LOVE this tutorial... great stuff. Everything I've used so far is working perfectly, except for this issue. I'm actually using rules to populate the ticket id number field (field_printable_tid), but unfortunately tokens don't work with rules when populating the barcode field. So I tried the following to throw into uc conditional actions. It's not populating the barcode field at all (field_printable_barcode).

I used a "display message" field on checkout, so I know uc conditional actions works fine. I tried populating another field (field_print_orderid) with a static number, it didn't populate. I'm assuming my problem is within the first 4 lines of this code, but I can't figure it out. Any ideas? Help is very much appreciated, this is baffling me.

if (isset($order)) {
  foreach ($order->products as $product) {
    if (isset($product->data['node_checkout_nid'])) {
      $node = node_load($product->data['node_checkout_nid']);
      $node->field_printable_barcode['0']['barcode'] = 3;
      node_save($node);
    }
  }
}
Gp
Gp's picture
Offline
Joined: 03/08/2012
Juice: 3
Ticket count down

We are doing a web base set up where we are selling tickets on line however we can't figure out a count down devise when tickets are purchased. Help anyone. Thanks gp

arvana's picture
Offline
Joined: 12/17/2010
Juice: 26
Stock

Just set the product to track stock, set the total number of tickets you have available as the initial stock, and as they are sold the stock will count down automatically.

skystill's picture
Offline
Joined: 03/21/2012
Juice: 3
Little help plz :D

Hello,

Thanks for this great tutorial !!

It is possible to have the title or the SKU of the class product, on the ticket ?
I try to do a conditional action and rules action but it doesn't work.

This code should work ? but nothing happens.

if (isset($order)) {
  foreach ($order->products as $product) {
    if (isset($product->data['node_checkout_nid'])) {
      $node = node_load($product->data['node_checkout_nid']);
      $node->field_bdr_desc['0']['value'] = "Title or SKU value" ;
      node_save($node);
    }
  }
}

Someone can help me ?
how do you proceed ?

Best regards.

snoop168's picture
Offline
Joined: 08/10/2012
Juice: 3
no need for user input

I am looking to sell tickets that don't necessarily need any user input, so for example they could enter a ticket into the cart and change the qty to whatever they want, the only thing i need is the ability to assign a unique number to each ticket and let them print each ticket out. Any way to do this by following most of these instructions. Basically i am not sure if i would need the uc_checkout_node module or not since I really don't need to prompt the user for anything but when the item is sold it must somehow save a unique value somewhere and generate the bar code based on the unique value.

end user's picture
Offline
Joined: 01/11/2008
Juice: 1738
snoop168 wrote: I am looking
snoop168 wrote:

I am looking to sell tickets that don't necessarily need any user input, so for example they could enter a ticket into the cart and change the qty to whatever they want, the only thing i need is the ability to assign a unique number to each ticket and let them print each ticket out. Any way to do this by following most of these instructions. Basically i am not sure if i would need the uc_checkout_node module or not since I really don't need to prompt the user for anything but when the item is sold it must somehow save a unique value somewhere and generate the bar code based on the unique value.

Have a look at these modules and see if they can help

http://drupal.org/project/serial

http://drupal.org/project/uc_product_keys (D6 only atm)