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

