From 2d9649dc10f51ef856f281b7c5a9b138fb459085 Mon Sep 17 00:00:00 2001 From: Doug Bell Date: Fri, 6 Apr 2007 00:55:39 +0000 Subject: [PATCH] fix: EMS now keeps information about registration if a user logs out before they complete their transaction. --- docs/changelog/7.x.x.txt | 3 + docs/gotcha.txt | 21 +++ docs/upgrades/upgrade_7.3.14-7.3.15.pl | 16 ++ .../Asset/Wobject/EventManagementSystem.pm | 170 +++++++++++------- lib/WebGUI/Commerce/Item/Event.pm | 29 +-- lib/WebGUI/i18n/English/Asset_Calendar.pm | 4 +- 6 files changed, 167 insertions(+), 76 deletions(-) diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 337430d91..521262892 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -1,6 +1,9 @@ 7.3.15 - fix: modified Form/Textarea.pm to use -min versions of YUI javascript libraries in order to speed up page load times - fix: fixed an error in the groups/db system where removing a dblink connected to a group would produce a fatal error + - fix: Event Management System -- No longer uses session scratch to save + purchase information, which breaks things when a user logs out before + they complete their transaction. 7.3.14 diff --git a/docs/gotcha.txt b/docs/gotcha.txt index 20d14eb33..2190926d1 100644 --- a/docs/gotcha.txt +++ b/docs/gotcha.txt @@ -7,6 +7,27 @@ upgrading from one version to the next, or even between multiple versions. Be sure to heed the warnings contained herein as they will save you many hours of grief. +7.3.15 +-------------------------------------------------------------------- + + * The Event Management System now uses an extra table to store + information about events in the user's cart. This fixes a bug + where a user that logs out after adding events to their cart but + before they complete their transaction will be charged for their + events but not registered for them. + + Existing sessions affected by this bug are not fixed, so there may still + be errors. This SQL query will get the session IDs of the + sessions affected by this bug: + + select distinct(sessionId) + from shoppingCart + where itemId IN (SELECT productId from EventManagementSystem_products) + AND sessionId IN (SELECT distinct(sessionId) FROM userSessionScratch WHERE name LIKE "purchaseId%"); + + You may want to expire these sessions from the Admin Console > + Active Sessions screen. + 7.3.12 -------------------------------------------------------------------- diff --git a/docs/upgrades/upgrade_7.3.14-7.3.15.pl b/docs/upgrades/upgrade_7.3.14-7.3.15.pl index e13a7b7d9..3efa9d6f7 100644 --- a/docs/upgrades/upgrade_7.3.14-7.3.15.pl +++ b/docs/upgrades/upgrade_7.3.14-7.3.15.pl @@ -21,6 +21,7 @@ my $quiet; # this line required my $session = start(); # this line required # upgrade functions go here +addEmsSessionPurchaseTable($session); finish($session); # this line required @@ -32,6 +33,21 @@ finish($session); # this line required # # and here's our code #} +#---------------------------------------------------------------------------- + +sub addEmsSessionPurchaseTable { + my $session = shift; + print "\tAdding EMS Session-to-purchase reference table..."; + $session->db->write( + "CREATE TABLE IF NOT EXISTS EventManagementSystem_sessionPurchaseRef ( + sessionId VARCHAR(22) BINARY, + purchaseId VARCHAR(22) BINARY, + badgeId VARCHAR(22) BINARY, + PRIMARY KEY (sessionId, purchaseId, badgeId) + )" + ); + print "OK!\n"; +} # ---- DO NOT EDIT BELOW THIS LINE ---- diff --git a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm index 9f84314d7..e8384ddf9 100644 --- a/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm +++ b/lib/WebGUI/Asset/Wobject/EventManagementSystem.pm @@ -972,7 +972,7 @@ sub removeFromScratchCart { # if ($event eq $self->session->scratch->get('currentMainEvent')) { # return $self->resetScratchCart(); # } - my $currentPurchase = $self->session->scratch->get('purchaseId'.$self->session->scratch->get('currentPurchaseCounter')); + my $currentPurchase = $self->session->scratch->get('currentPurchase'); if ($currentPurchase ne "") { my $shoppingCart = WebGUI::Commerce::ShoppingCart->new($self->session); my ($items, $nothing) = $shoppingCart->getItems; @@ -1328,7 +1328,7 @@ sub validateEditEventForm { if ($self->session->form->get("pid") eq "meetmymaker") { push (@{$errors}, { type => "special", - message => "+4F]Y(&UA9&4@;64", + message => '/26T@new($self->session,'Asset_EventManagementSystem'); my $var = shift; $var->{'cart.purchaseLoop'} = []; - my $i; - for ( $i=0; $i < 25;$i++) { - my $purchase = {}; - $purchase->{purchaseId} = $self->session->scratch->get("purchaseId".$i); - next unless $purchase->{purchaseId}; - $purchase->{badgeId} = $self->session->scratch->get("badgeId".$i); + my $purchases = $self->session->db->buildArrayRefOfHashRefs( + "SELECT purchaseId, badgeId FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=?", + [$self->session->getId] + ); + for my $purchase (@{ $purchases }) { # so we don't show the badge we're currently editing - next if ($i eq $self->session->scratch->get("currentPurchaseCounter")); - my $theseRegs = $self->session->db->buildArrayRefOfHashRefs("select r.*, p.price, q.passId, q.passType from EventManagementSystem_registrations as r, EventManagementSystem_products as q, products as p where p.productId=r.productId and r.badgeId=? and r.returned=0 and r.purchaseId=? and q.productId=r.productId",[$purchase->{badgeId},$purchase->{purchaseId}]); + next if ($purchase->{purchaseId} eq $self->session->scratch->get("currentPurchase")); + my $theseRegs + = $self->session->db->buildArrayRefOfHashRefs( + "select r.*, p.price, q.passId, q.passType + from EventManagementSystem_registrations as r, + EventManagementSystem_products as q, + products as p + where p.productId=r.productId + and r.badgeId=? + and r.returned=0 + and r.purchaseId=? + and q.productId=r.productId", + [$purchase->{badgeId},$purchase->{purchaseId}] + ); my @currentEvents; - $purchase->{registrantInfoLoop} = $self->session->db->buildArrayRefOfHashRefs("select * from EventManagementSystem_badges where badgeId=?",[$purchase->{badgeId}]); + $purchase->{registrantInfoLoop} + = $self->session->db->buildArrayRefOfHashRefs( + "select * from EventManagementSystem_badges where badgeId=?", + [$purchase->{badgeId}] + ); foreach (@$theseRegs) { - my ($isChild) = $self->session->db->quickArray("select prerequisiteId from EventManagementSystem_products where productId = ?",[$_->{productId}]); + my ($isChild) + = $self->session->db->quickArray( + "select prerequisiteId from EventManagementSystem_products where productId = ?", + [$_->{productId}] + ); $purchase->{'purchase.mainEventTitle'} = $self->getEventName($_->{productId}) unless $isChild; - ($purchase->{alreadyPurchasedBadge}) = $self->session->db->quickArray("select p.transactionId from EventManagementSystem_purchases as p, transaction as t where p.purchaseId = ? and t.transactionId=p.transactionId and t.status='Completed'",[$_->{productId}]) unless $isChild; - push(@currentEvents,$_->{productId}); + ($purchase->{alreadyPurchasedBadge}) + = $self->session->db->quickArray( + "select p.transactionId + from EventManagementSystem_purchases as p, + transaction as t + where p.purchaseId = ? + and t.transactionId=p.transactionId + and t.status='Completed'", + [$_->{productId}] + ) unless $isChild; + push @currentEvents,$_->{productId}; } - my @pastEvents = $self->session->db->buildArray("select r.productId from EventManagementSystem_registrations as r, EventManagementSystem_purchases as p, transaction as t where r.returned=0 and r.badgeId=? and t.transactionId=p.transactionId and t.status='Completed' and p.purchaseId=r.purchaseId group by productId",[$purchase->{badgeId}]); + my @pastEvents + = $self->session->db->buildArray( + "select r.productId + from EventManagementSystem_registrations as r, + EventManagementSystem_purchases as p, + transaction as t + where r.returned=0 + and r.badgeId=? + and t.transactionId=p.transactionId + and t.status='Completed' + and p.purchaseId=r.purchaseId + group by productId", + [$purchase->{badgeId}] + ); push(@currentEvents,@pastEvents); $purchase->{newPrice} = 0; foreach (@$theseRegs) { @@ -1449,10 +1490,10 @@ sub addCartVars { $purchase->{newPrice} += $_->{price}; } } - $purchase->{editIcon} = $self->session->icon->edit("func=addEventsToBadge;bid=".$purchase->{badgeId}.";purchaseCounter=".$i, $self->get('url')); - $purchase->{deleteIcon} = $self->session->icon->delete("func=addEventsToBadge;bid=none;purchaseCounter=".$i,$self->get('url'),$i18n->get('confirm delete purchase')); - $purchase->{'edit.url'} = $self->getUrl("func=addEventsToBadge;bid=".$purchase->{badgeId}.";purchaseCounter=".$i); - $purchase->{'delete.url'} = $self->getUrl("func=addEventsToBadge;bid=none;purchaseCounter=".$i); + $purchase->{editIcon} = $self->session->icon->edit("func=addEventsToBadge;bid=".$purchase->{badgeId}.";purchaseId=".$purchase->{purchaseId}, $self->get('url')); + $purchase->{deleteIcon} = $self->session->icon->delete("func=addEventsToBadge;bid=none;purchaseId=".$purchase->{purchaseId},$self->get('url'),$i18n->get('confirm delete purchase')); + $purchase->{'edit.url'} = $self->getUrl("func=addEventsToBadge;bid=".$purchase->{badgeId}.";purchaseId=".$purchase->{purchaseId}); + $purchase->{'delete.url'} = $self->getUrl("func=addEventsToBadge;bid=none;purchaseId=".$purchase->{purchaseId}); push(@{$var->{'cart.purchaseLoop'}},$purchase); } $var->{'checkoutUrl'} = $self->getUrl("func=checkout"); @@ -1469,10 +1510,10 @@ sub www_emptyCart { my $self = shift; my $shoppingCart = WebGUI::Commerce::ShoppingCart->new($self->session); $shoppingCart->empty; - foreach (0..25) { - $self->session->scratch->delete('purchaseId'.$_); - $self->session->scratch->delete('badgeId'.$_); - } + $self->session->db->write( + "DELETE FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=?", + [$self->session->getId] + ); return $self->www_resetScratchCart(); } @@ -2238,41 +2279,49 @@ sub www_addEventsToBadge { } $self->session->scratch->set('EMS_add_purchase_badgeId',$bid); my @pastEvents = $self->session->db->buildArray("select r.productId from EventManagementSystem_registrations as r, EventManagementSystem_purchases as p, transaction as t where r.returned=0 and r.badgeId=? and t.transactionId=p.transactionId and t.status='Completed' and p.purchaseId=r.purchaseId group by productId",[$bid]); - my $purchaseCounter = $self->session->form->process('purchaseCounter'); $self->session->scratch->set('EMS_add_purchase_events',join("\n",@pastEvents)); - if ($purchaseCounter ne "") { + my $purchaseId = $self->session->form->process('purchaseId'); + if ($purchaseId ne "") { # if we're loading a badge that's in the cart, put its stuff in the scratch cart along with the already-purchased events for this badgeId. - $self->session->scratch->set("currentPurchaseCounter",$purchaseCounter); - my $theseRegs = $self->session->db->buildArrayRefOfHashRefs("select r.*, p.price, q.prerequisiteId from EventManagementSystem_registrations as r, EventManagementSystem_products as q, products as p where p.productId=r.productId and q.productId=r.productId and r.returned=0 and r.badgeId=?",[$self->session->scratch->get("badgeId".$purchaseCounter)]); + $self->session->scratch->set("currentPurchase",$purchaseId); + my ($badgeId) + = $self->session->db->quickArray( + "SELECT badgeId FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=? AND purchaseId=?", + [$self->session->getId,$purchaseId] + ); + my $theseRegs = $self->session->db->buildArrayRefOfHashRefs("select r.*, p.price, q.prerequisiteId from EventManagementSystem_registrations as r, EventManagementSystem_products as q, products as p where p.productId=r.productId and q.productId=r.productId and r.returned=0 and r.badgeId=?",[$badgeId]); foreach (@$theseRegs) { push(@pastEvents,$_->{productId}) unless isIn($_->{productId},@pastEvents); $eventId = $_->{productId} unless $_->{prerequisiteId}; } - $self->removePurchaseFromCart($self->session->scratch->get("purchaseId".$purchaseCounter)); + $self->removePurchaseFromCart($purchaseId); + # Remove from the sessionPurchaseRef, it will be added again when + # the user is finished and clicks "Add to cart" again + $self->session->db->write( + "DELETE FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=? AND purchaseId=? AND badgeId=?", + [$self->session->getId, $purchaseId, $badgeId] + ); } else { # gotta use the existing purchaseId, b/c we're loading a completed purchase. my ($purchaseId) = $self->session->db->quickArray("select purchaseId from EventManagementSystem_registrations where badgeId=? and productId=? and purchaseId != '' and returned=0 and purchaseId is not null limit 1",[$bid,$eventId]); - my $counter = 0; - while (1) { - unless ($self->session->scratch->get("purchaseId".$counter)) { - $self->session->scratch->set("purchaseId".$counter, $purchaseId); - $self->session->scratch->set("badgeId".$counter, $bid); - $self->session->scratch->set("currentPurchaseCounter",$counter); - last; - } - $counter++; - } + $self->session->scratch->set("currentPurchase",$purchaseId); + $self->session->db->write( + "INSERT INTO EventManagementSystem_sessionPurchaseRef (sessionId, purchaseId, badgeId) VALUES (?,?,?)", + [$self->session->getId, $purchaseId, $bid] + ); } $self->session->scratch->set('EMS_scratch_cart',join("\n",@pastEvents)); $self->session->scratch->set('currentMainEvent',$eventId); $self->session->scratch->set('currentBadgeId',$bid); return $self->www_search(); } else { - my $purchaseCounter = $self->session->form->process('purchaseCounter'); - if ($purchaseCounter ne "") { - my $purchaseIdToDelete = $self->session->scratch->get('purchaseId'.$purchaseCounter); - $self->removePurchaseFromCart($purchaseIdToDelete); - $self->session->scratch->delete('purchaseId'.$purchaseCounter); + my $purchaseId = $self->session->form->process('purchaseId'); + if ($purchaseId ne "") { + $self->removePurchaseFromCart($purchaseId); + $self->session->db->write( + "DELETE FROM EventManagementSystem_sessionPurchaseRef WHERE purchaseId=?", + [$purchaseId] + ); } } return $self->www_resetScratchCart(); @@ -2595,23 +2644,17 @@ sub saveRegistration { $shoppingCart->add($eventId, 'Event'); $addedAny = 1; } - #Our item plug-in needs to be able to associate these records with the result of the payment attempt - my $counter = 0; - while (1) { - unless ($self->session->scratch->get("purchaseId".$counter)) { - $self->session->scratch->set("purchaseId".$counter, $purchaseId); - $self->session->scratch->set("badgeId".$counter, $badgeId); - $self->session->scratch->delete('purchaseId'.$self->session->scratch->get('currentPurchaseCounter')); - last; - } - $counter++; - } - $self->emptyScratchCart; - $self->session->scratch->delete('EMS_add_purchase_badgeId'); - $self->session->scratch->delete('EMS_add_purchase_events'); - $self->session->scratch->delete('currentBadgeId'); - $self->session->scratch->delete('currentMainEvent'); - $self->session->scratch->delete('currentPurchaseCounter'); + #Our item plug-in needs to be able to associate these records with the result of the payment attempt + $self->session->db->write( + "INSERT INTO EventManagementSystem_sessionPurchaseRef (sessionId, purchaseId, badgeId) VALUES (?,?,?)", + [$self->session->getId, $purchaseId, $badgeId] + ); + $self->emptyScratchCart; + $self->session->scratch->delete('EMS_add_purchase_badgeId'); + $self->session->scratch->delete('EMS_add_purchase_events'); + $self->session->scratch->delete('currentBadgeId'); + $self->session->scratch->delete('currentMainEvent'); + $self->session->scratch->delete('currentPurchase'); # if ($self->session->form->get('checkoutNow')) { # srand; @@ -2629,8 +2672,11 @@ sub www_resetScratchCart { $self->session->scratch->delete('EMS_add_purchase_events'); $self->session->scratch->delete('currentMainEvent'); $self->session->scratch->delete('currentBadgeId'); - $self->session->scratch->delete('purchaseId'.$self->session->scratch->get('currentPurchaseCounter')); - $self->session->scratch->delete('currentPurchaseCounter'); + $self->session->db->write( + "DELETE FROM EventManagementSystem_sessionPurchaseRef WHERE purchaseId=?", + [$self->session->scratch->get('currentPurchase')] + ); + $self->session->scratch->delete('currentPurchase'); return $self->www_view; } diff --git a/lib/WebGUI/Commerce/Item/Event.pm b/lib/WebGUI/Commerce/Item/Event.pm index 97c22d926..8d26da6a7 100644 --- a/lib/WebGUI/Commerce/Item/Event.pm +++ b/lib/WebGUI/Commerce/Item/Event.pm @@ -43,20 +43,25 @@ sub handler { my $self = shift; my $transactionId = shift; #mark all purchaseIds as paid - my $counter; - for ($counter = 0 ; $counter < 50 ; $counter++ ) { - my $purchaseId; - if ($purchaseId = $self->session->scratch->get("purchaseId".$counter)) { - $self->session->db->setRow('EventManagementSystem_purchases', 'purchaseId', {'purchaseId'=>$purchaseId, 'transactionId'=>$transactionId}, $purchaseId); - my $theseRegs = $self->session->db->buildArrayRefOfHashRefs("select * from EventManagementSystem_registrations where purchaseId=?",[$purchaseId]); - foreach (@$theseRegs) { - # clean up the duplicate registrations, if any. - $self->session->db->write("delete from EventManagementSystem_registrations where badgeId=? and productId=? and registrationId != ?",[$_->{badgeId},$_->{productId},$_->{registrationId}]); - } - $self->session->scratch->delete("purchaseId".$counter); - } + my $purchases + = $self->session->db->buildArrayRefOfHashRefs( + "SELECT purchaseId FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=?", + [$self->session->getId] + ); + for my $purchase (@$purchases) { + my $purchaseId = $purchase->{purchaseId}; + $self->session->db->setRow('EventManagementSystem_purchases', 'purchaseId', {'purchaseId'=>$purchaseId, 'transactionId'=>$transactionId}, $purchaseId); + my $theseRegs = $self->session->db->buildArrayRefOfHashRefs("select * from EventManagementSystem_registrations where purchaseId=?",[$purchaseId]); + foreach (@$theseRegs) { + # clean up the duplicate registrations, if any. + $self->session->db->write("delete from EventManagementSystem_registrations where badgeId=? and productId=? and registrationId != ?",[$_->{badgeId},$_->{productId},$_->{registrationId}]); + } } + $self->session->db->write( + "DELETE FROM EventManagementSystem_sessionPurchaseRef WHERE sessionId=?", + [$self->session->getId] + ); } #------------------------------------------------------------------- diff --git a/lib/WebGUI/i18n/English/Asset_Calendar.pm b/lib/WebGUI/i18n/English/Asset_Calendar.pm index 600baba5e..cc993fa1f 100755 --- a/lib/WebGUI/i18n/English/Asset_Calendar.pm +++ b/lib/WebGUI/i18n/English/Asset_Calendar.pm @@ -111,12 +111,12 @@ our $I18N = { ##### Group to add/edit events ##### 'groupIdEventEdit label' => { - message => q{Who can add/edit Events?}, + message => q{Who can add Events?}, lastUpdated => 0, context => q{The label for the Group to Edit Events field.}, }, 'groupIdEventEdit description' => { - message => q{Members of this group can add and edit Events in this calendar.}, + message => q{Members of this group can add Events to this calendar.}, lastUpdated => 0, context => q{Hover Help for the Group to Edit Events field.}, },