0.15_15 commit r0_15_15
authorTony Cook <tony@develop-help.com>
Wed, 29 Jun 2005 06:38:48 +0000 (06:38 +0000)
committertony <tony@45cb6cf1-00bc-42d2-bb5a-07f51df49f94>
Wed, 29 Jun 2005 06:38:48 +0000 (06:38 +0000)
28 files changed:
MANIFEST
Makefile
schema/bse.sql
site/cgi-bin/admin/subs.pl
site/cgi-bin/modules/BSE/DB/Mysql.pm
site/cgi-bin/modules/BSE/Edit/Article.pm
site/cgi-bin/modules/BSE/Edit/Seminar.pm
site/cgi-bin/modules/BSE/Generate/Seminar.pm
site/cgi-bin/modules/BSE/Shop/Util.pm
site/cgi-bin/modules/BSE/TB/OrderItem.pm
site/cgi-bin/modules/BSE/TB/Seminar.pm
site/cgi-bin/modules/BSE/TB/SeminarSession.pm
site/cgi-bin/modules/BSE/UI/AdminSeminar.pm
site/cgi-bin/modules/BSE/UI/Shop.pm
site/cgi-bin/modules/DevHelp/Date.pm
site/cgi-bin/modules/SiteUser.pm
site/cgi-bin/shop.pl
site/docs/bse.pod
site/templates/admin/addattendee1.tmpl [new file with mode: 0644]
site/templates/admin/addattendee2.tmpl [new file with mode: 0644]
site/templates/admin/users/edit.tmpl
site/templates/cart_base.tmpl
site/templates/checkoutfinal_base.tmpl
site/templates/checkoutnew_base.tmpl
site/templates/location.tmpl [new file with mode: 0644]
site/templates/seminars/seminar.tmpl [new file with mode: 0644]
site/util/upgrade_mysql.pl
test.cfg

index 8b9d772ead3f7d7827301b8bd3231f45f4d71e8b..16f2412fe2de775cdd79da74964db678838d8312 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -248,6 +248,8 @@ site/htdocs/js/validate.js
 site/templates/1/shop_multicat.tmpl
 site/templates/1/sitemap.tmpl
 # site/templates/admin/add_product.tmpl
+site/templates/admin/addattendee1.tmpl
+site/templates/admin/addattendee2.tmpl
 site/templates/admin/addgroup.tmpl
 site/templates/admin/adduser.tmpl
 # site/templates/admin/article_custom.tmpl
@@ -360,6 +362,7 @@ site/templates/index2.tmpl
 site/templates/interest/askagain_base.tmpl
 site/templates/interest/confirm_base.tmpl
 site/templates/interest/error_base.tmpl
+site/templates/location.tmpl
 site/templates/lowmap.tmpl
 site/templates/mailconfirm.tmpl
 site/templates/mailorder.tmpl
@@ -372,6 +375,7 @@ site/templates/menu/menu5.tmpl
 site/templates/printable/printable.tmpl
 site/templates/printable/wap.tmpl
 site/templates/search_base.tmpl
+site/templates/seminars/seminar.tmpl
 site/templates/shop_help.tmpl
 site/templates/shop_sect.tmpl
 site/templates/shopitem.tmpl
index e5182f9819442f877ea3a83c0c12e98a5ec7efca..a4c7f2090050e778d8b65530a2e9d303650b7753 100755 (executable)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.15_14
+VERSION=0.15_15
 DISTNAME=bse-$(VERSION)
 DISTBUILD=$(DISTNAME)
 DISTTAR=../$(DISTNAME).tar
index 60efef42eef9734ebe60860373e7b065429b91d7..60672b3ba4e6e02acdcf6062601cfe243b3b11a4 100644 (file)
@@ -319,6 +319,9 @@ create table order_item (
   -- transferred from the subscription
   max_lapsed integer not null default 0,
 
+  -- session for a seminar
+  session_id integer not null default -1,
+
   primary key (id),
   index order_item_order(orderId, id)
 );
index eb799b09ece71dced38ef171147c984e47e3a581..474b77042d6138b0720ce922afa0b0de8d9a43b5 100755 (executable)
@@ -74,6 +74,7 @@ sub list {
      BSE::Util::Tags->make_iterator(\@subs, 'subscription', 'subscriptions',
                                    \$subindex),
      BSE::Util::Tags->secure($req),
+     BSE::Util::Tags->admin(\%acts, $cfg),
      message => sub { CGI::escapeHTML($message) },
      recipient_count => [ \&tag_list_recipient_count, \@subs, \$subindex ],
     );
index b719d56795e8be8f96a94c07cacd6089b1f31f10..add47352906b198655d37e53f8b38dfba557ba5a 100644 (file)
@@ -86,7 +86,7 @@ SQL
    getOrderItemByOrderId => 'select * from order_item where orderId = ?',
    addOrder => 'insert orders values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    replaceOrder => 'replace orders values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
-   addOrderItem => 'insert order_item values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
+   addOrderItem => 'insert order_item values(null,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)',
    getOrderByUserId => 'select * from orders where userId = ?',
    deleteOrdersItems => 'delete from order_item where orderId = ?',
 
@@ -363,7 +363,7 @@ SQL
    Seminars => <<SQL,
 select ar.*, pr.*, se.*
   from article ar, product pr, bse_seminars se
-  where ar.id = pr.articleId and ar.id = se.articleId
+  where ar.id = pr.articleId and ar.id = se.seminar_id
 SQL
    addSeminar => 'insert bse_seminars values(?,?)',
    replaceSeminar => 'replace bse_seminars values(?,?)',
@@ -371,6 +371,18 @@ SQL
 select ar.*, pr.*, se.*
   from article ar, product pr, bse_seminars se
   where id = ? and ar.id = pr.articleId and ar.id = se.seminar_id
+SQL
+   'Locations.seminarFuture' => <<SQL,
+select distinct lo.*
+  from bse_locations lo, bse_seminar_sessions ss
+where ss.seminar_id = ? and ss.when_at > ?
+  and ss.location_id = lo.id
+order by lo.description
+SQL
+   'Locations.session_id' => <<SQL,
+select lo.*
+  from bse_locations lo, bse_seminar_sessions ss
+where lo.id = ss.location_id and ss.id = ?
 SQL
 
    seminarSessionInfo => <<SQL,
@@ -378,6 +390,13 @@ select se.*, lo.description
   from bse_seminar_sessions se, bse_locations lo
   where se.seminar_id = ? and se.location_id = lo.id
 order by when_at desc
+SQL
+   seminarFutureSessionInfo => <<SQL,
+select se.*, lo.description, lo.room, lo.street1, lo.street2, lo.suburb, 
+    lo.state, lo.country, lo.postcode, lo.public_notes
+  from bse_seminar_sessions se, bse_locations lo
+  where se.seminar_id = ? and se.when_at > ? and se.location_id = lo.id
+order by when_at desc
 SQL
    addSeminarSession => 'insert bse_seminar_sessions values(null,?,?,?,?)',
    replaceSeminarSession => 'replace bse_seminar_sessions values(?,?,?,?,?)',
@@ -386,10 +405,19 @@ SQL
    getSeminarSessionByLocation_idAndWhen_at => <<SQL,
 select * from bse_seminar_sessions
   where location_id = ? and when_at = ?
+SQL
+   getSeminarSessionBySeminar_id => <<SQL,
+select * from bse_seminar_sessions
+  where seminar_id = ?
 SQL
    'SeminarSessions.futureSessions' => <<SQL,
 select * from bse_seminar_sessions
   where seminar_id = ? and when_at >= ?
+SQL
+   'SeminarSessions.futureSeminarLocation' => <<SQL,
+select *
+  from bse_seminar_sessions
+  where seminar_id = ? and location_id = ? and when_at > ?
 SQL
    'SiteUsers.sessionBookings' => <<SQL,
 select su.* from site_users su, bse_seminar_bookings sb
@@ -408,17 +436,22 @@ SQL
 select * from bse_seminar_bookings where session_id = ?
 SQL
    seminarSessionBookUser => <<SQL,
-insert bse_seminar_bookings values(?,?)
+insert bse_seminar_bookings values(?,?,?)
 SQL
    seminarSessionRollCallEntries => <<SQL,
 select bo.roll_present, su.id, su.userId, su.name1, su.name2, su.email
   from bse_seminar_bookings bo, site_users su
 where bo.session_id = ? and bo.siteuser_id = su.id
 SQL
-  updateSessionRollPresent => <<SQL
+  updateSessionRollPresent => <<SQL,
 update bse_seminar_bookings
   set roll_present = ?
   where session_id = ? and siteuser_id = ?
+SQL
+  userSeminarSessionBookings => <<SQL,
+select session_id 
+  from bse_seminar_bookings sb, bse_seminar_sessions ss
+where ss.seminar_id = ? and ss.id = sb.session_id and siteuser_id = ?
 SQL
   );
 
index 797077f91ecc3ae28e793c0d83ce59e74f69e014..1cd9465cbcd4acc316894b2fb7eafc14a0990223 100644 (file)
@@ -1256,13 +1256,6 @@ sub validate {
   custom_class($self->{cfg})
     ->article_validate($data, undef, $self->typename, $errors);
 
-  if (!defined $data->{parentid} || $data->{parentid} eq '') {
-    $errors->{parentid} = "Please select a parent";
-  }
-  elsif ($data->{parentid} !~ /^(?:-1|\d+)$/) {
-    $errors->{parentid} = "Invalid parent selection (template bug)";
-  }
-
   return !keys %$errors;
 }
 
@@ -1345,6 +1338,12 @@ sub save_new {
 
   my $msg;
   my %errors;
+  if (!defined $data{parentid} || $data{parentid} eq '') {
+    $errors{parentid} = "Please select a parent";
+  }
+  elsif ($data{parentid} !~ /^(?:-1|\d+)$/) {
+    $errors{parentid} = "Invalid parent selection (template bug)";
+  }
   $self->validate(\%data, $articles, \%errors)
     or return $self->add_form($req, $articles, $msg, \%errors);
 
@@ -1398,17 +1397,16 @@ sub save_new {
       or $data{$col} = $self->default_value($req, \%data, $col);
   }
 
-  print STDERR "release cgi ", $cgi->param('release'), " data $data{release}\n";
+  for my $col (qw(release expire)) {
+    $data{$col} = sql_date($data{$col});
+  }
+
   # these columns are handled a little differently
   for my $col (qw(release expire threshold summaryLength )) {
     $data{$col} 
       or $data{$col} = $self->default_value($req, \%data, $col);
   }
 
-  for my $col (qw(release expire)) {
-    $data{$col} = sql_date($data{$col});
-  }
-
   shift @columns;
   my $article = $table_object->add(@data{@columns});
 
index f37aa54a82a2d05ab6cf3f45d76d1e2fabe5b394..92974ff57916944368ccb9f717930da7cc5b8cbb 100644 (file)
@@ -7,6 +7,7 @@ use BSE::Util::SQL qw(now_sqldatetime);
 use DevHelp::Date qw(dh_parse_date_sql dh_parse_time_sql);
 use constant SECT_SEMSESSION_VALIDATION => 'BSE Seminar Session Validation';
 use DevHelp::HTML qw(escape_html);
+use BSE::Util::Iterate;
 
 sub article_actions {
   my ($self) = @_;
@@ -24,10 +25,6 @@ sub article_actions {
     );
 }
 
-sub base_template_dirs {
-  return ( "seminar" );
-}
-
 sub edit_template { 
   my ($self, $article, $cgi) = @_;
 
@@ -593,5 +590,21 @@ sub req_takesessionrolesave {
   return $self->refresh($article, $cgi, undef, "Roll saved");
 }
 
+sub base_template_dirs {
+  return ( "seminars" );
+}
+
+sub extra_templates {
+  my ($self, $article) = @_;
+
+  my @extras;
+
+  my $extras = $self->{cfg}->entry('seminars', 'extra_templates');
+  push @extras, grep /\.(tmpl|html)$/i, split /,/, $extras
+    if $extras;
+
+  return @extras;
+}
+
 1;
 
index 0aec0cb0375eefb142f643fca449855a2f261ab4..7c165da54cd58c8cd934c8b3001f550226b01cb5 100644 (file)
@@ -4,6 +4,7 @@ use base 'Generate::Product';
 use BSE::TB::Seminars;
 use DevHelp::HTML;
 use BSE::Util::Tags qw(tag_hash);
+use BSE::Util::Iterate;
 
 sub baseActs {
   my ($self, $articles, $acts, $seminar, $embedded) = @_;
@@ -11,12 +12,41 @@ sub baseActs {
   unless ($seminar->isa('BSE::TB::Seminar')) {
     $seminar = BSE::TB::Seminars->getByPkey($seminar->{id});
   }
+  my $it = BSE::Util::Iterate->new;
+  my $location;
   return
     (
      $self->SUPER::baseActs($articles, $acts, $seminar, $embedded),
      seminar => [ \&tag_hash, $seminar ],
      admin => [ tag_admin => $self, $seminar, 'seminar', $embedded ],
+     $it->make_iterator([ \&iter_sessions, $seminar ], 'session', 'sessions'),
+     $it->make_iterator
+     ([ \&iter_locations, $seminar ], 'location', 'locations',
+      undef, undef, undef, \$location),
+     $it->make_iterator
+     ([ \&iter_location_sessions, $seminar, \$location ], 'location_session',
+      'location_sessions', undef, undef, 'nocache'),
     );
 }
 
+sub iter_sessions {
+  my ($seminar) = @_;
+
+  $seminar->future_session_info;
+}
+
+sub iter_locations {
+  my ($seminar) = @_;
+
+  $seminar->future_locations;
+}
+
+sub iter_location_sessions {
+  my ($seminar, $rlocation) = @_;
+
+  $$rlocation or return;
+
+  $seminar->future_location_sessions($$rlocation);
+}
+
 1;
index 592e1f0747eec42307b7cb0143e79afa944484de..9f77aea026c91526fae1e34aa1592aeb5d740da5 100644 (file)
@@ -10,6 +10,7 @@ use BSE::Util::SQL qw(now_sqldate);
 use BSE::Util::Tags;
 use BSE::CfgInfo qw(custom_class);
 use Carp 'confess';
+use DevHelp::HTML qw(escape_html);
 
 # returns a list of tags which display the cart details
 sub shop_cart_tags {
@@ -26,7 +27,10 @@ sub shop_cart_tags {
     require 'SiteUsers.pm';
     $user = SiteUsers->getBy(userId=>$session->{userid});
   }
-
+  my $sem_session;
+  my $location;
+  my $item;
+  my $product;
   return
     (
      BSE::Util::Tags->basic($acts, $q, $cfg),
@@ -39,8 +43,16 @@ sub shop_cart_tags {
         $option_index = -1;
         @options = cart_item_opts($cart->[$item_index], 
                                   $cart_prods->[$item_index]);
+        undef $sem_session;
+        undef $location;
+        $item = $cart->[$item_index];
+        $product = $cart_prods->[$item_index];
         return 1;
        }
+       undef $item;
+       undef $sem_session;
+       undef $product;
+       undef $location;
        return 0;
      },
      item => 
@@ -64,11 +76,51 @@ sub shop_cart_tags {
      option => sub { CGI::escapeHTML($options[$option_index]{$_[0]}) },
      ifOptions => sub { @options },
      options => sub { nice_options(@options) },
+     session => [ \&tag_session, \$item, \$sem_session ],
+     location => [ \&tag_location, \$item, \$location ],
      custom_class($cfg)
      ->checkout_actions($acts, $cart, $cart_prods, $session->{custom}, $q, $cfg),
     );  
 }
 
+sub tag_session {
+  my ($ritem, $rsession, $arg) = @_;
+
+  $$ritem or return '';
+
+  $$ritem->{session_id} or return '';
+
+  unless ($$rsession) {
+    require BSE::TB::SeminarSessions;
+    $$rsession = BSE::TB::SeminarSessions->getByPkey($$ritem->{session_id})
+      or return '';
+  }
+
+  my $value = $$rsession->{$arg};
+  defined $value or return '';
+
+  escape_html($value);
+}
+
+sub tag_location {
+  my ($ritem, $rlocation, $arg) = @_;
+
+  $$ritem or return '';
+
+  $$ritem->{session_id} or return '';
+
+  unless ($$rlocation) {
+    require BSE::TB::Locations;
+    ($$rlocation) = BSE::TB::Locations->getSpecial(session_id => $$ritem->{session_id})
+      or return '';
+  }
+
+  my $value = $$rlocation->{$arg};
+  defined $value or return '';
+
+  escape_html($value);
+}
+
 sub cart_item_opts {
   my ($cart_item, $product) = @_;
 
index 0077f0c2f82ed77b527667ff5eded886201bf926..5f3c335bb2073bc626365fa4940c22fe604ac212 100644 (file)
@@ -8,7 +8,8 @@ use vars qw/@ISA/;
 sub columns {
   return qw/id productId orderId units price wholesalePrice gst options
             customInt1 customInt2 customInt3 customStr1 customStr2 customStr3
-            title summary subscription_id subscription_period max_lapsed/;
+            title summary subscription_id subscription_period max_lapsed
+            session_id/;
 }
 
 1;
index 49502f067c1a5d3e8fda9ffc9db3926ff6203890..14afb4f0a6096324e62d62ae201506e748c93916 100644 (file)
@@ -19,7 +19,7 @@ sub sessions {
   my ($self) = @_;
 
   require BSE::TB::SeminarSessions;
-  BSE::TB::SeminarSessions->getBy(session_id => $self->{id});
+  BSE::TB::SeminarSessions->getBy(seminar_id => $self->{id});
 }
 
 sub future_sessions {
@@ -35,6 +35,12 @@ sub session_info {
   BSE::DB->query(seminarSessionInfo => $self->{id});
 }
 
+sub future_session_info {
+  my ($self) = @_;
+
+  BSE::DB->query(seminarFutureSessionInfo=>$self->{id}, now_sqldatetime());
+}
+
 sub add_session {
   my ($self, $when, $location) = @_;
 
@@ -51,4 +57,20 @@ sub add_session {
   return BSE::TB::SeminarSessions->add(@cols{@cols});
 }
 
+sub future_locations {
+  my ($self) = @_;
+
+  require BSE::TB::Locations;
+  return BSE::TB::Locations->getSpecial
+    (seminarFuture => $self->{id}, now_sqldatetime());
+}
+
+sub future_location_sessions {
+  my ($self, $location) = @_;
+
+  require BSE::TB::SeminarSessions;
+  return BSE::TB::SeminarSessions->getSpecial
+    (futureSeminarLocation => $self->{id}, $location->{id}, now_sqldatetime());
+}
+
 1;
index 2961c117d396d07abb9963c57c8fcc77391a582d..42691a9b3ed32976a2160cdc779505c2d398e64b 100644 (file)
@@ -40,7 +40,7 @@ sub replace_with {
     BSE::DB->query(seminarSessionBookedIds => $self->{id});
   for my $userid (@users_booked) {
     unless ($conflicts{$userid}) {
-      BSE::DB->run(seminarSessionBookUser => $other->{id}, $userid);
+      BSE::DB->run(seminarSessionBookUser => $other->{id}, $userid, 0);
     }
   }
   BSE::DB->run(cancelSeminarSessionBookings => $self->{id});
@@ -69,5 +69,14 @@ sub set_roll_present {
   BSE::DB->run(updateSessionRollPresent => $present, $self->{id}, $userid);
 }
 
+sub add_attendee {
+  my ($self, $user, $present) = @_;
+
+  $present ||= 0;
+  my $user_id = ref $user ? $user->{id} : $user;
+
+  BSE::DB->run(seminarSessionBookUser => $self->{id}, $user_id, $present);
+}
+
 1;
 
index 1e82ca09c47387d3690bf7f4bbe5caeb63d65a08..54b197180b7e61f014d2fb6229efdf58bd8f7e17 100644 (file)
@@ -20,6 +20,9 @@ my %rights =
    locdelete => 'bse_location_delete',
 #    detail => 'bse_subscr_detail',
 #    update => 'bse_subscr_update',
+   addattendseminar => 'bse_session_addattendee',
+   addattendsession => 'bse_session_addattendee',
+   addattendsave => 'bse_session_addattendee',
   );
 
 sub actions { \%rights }
@@ -263,4 +266,146 @@ sub _loclist_refresh {
   return $r;
 }
 
+sub req_addattendseminar {
+  my ($class, $req, $errors) = @_;
+
+  # make sure we're passed a valid siteuser_id
+  my $cgi = $req->cgi;
+  my $siteuser_id = $cgi->param('siteuser_id');
+  defined $siteuser_id && $siteuser_id =~ /^\d+$/
+    or return $class->req_loclist($req, { siteuser_id => 
+                                         "Missing or invalid siteuser_id" });
+  require SiteUsers;
+  my $siteuser = SiteUsers->getByPkey($siteuser_id)
+    or return $class->req_loclist($req, { siteuser_id => "Unknown siteuser_id" });
+  my $msg = $req->message($errors);
+  require BSE::TB::Seminars;
+  my @seminars = BSE::TB::Seminars->all;
+
+  my $it = BSE::Util::Iterate->new;
+  my %acts;
+  %acts =
+    (
+     BSE::Util::Tags->basic(\%acts, $req->cgi, $req->cfg),
+     BSE::Util::Tags->admin(\%acts, $req->cfg),
+     BSE::Util::Tags->secure($req),
+     $it->make_iterator(undef, 'seminar', 'seminars', \@seminars),
+     siteuser => [ \&tag_hash, $siteuser ],
+     msg => $msg,
+     message => $msg,
+     error_img => [ \&tag_error_img, $req->cfg, $errors ],
+    );
+  
+  return $req->dyn_response('admin/addattendee1.tmpl', \%acts);
+}
+
+sub req_addattendsession {
+  my ($class, $req, $errors) = @_;
+
+  # make sure we're passed a valid siteuser_id
+  my $cgi = $req->cgi;
+  my $siteuser_id = $cgi->param('siteuser_id');
+  defined $siteuser_id && $siteuser_id =~ /^\d+$/
+    or return $class->req_loclist($req, { siteuser_id => 
+                                         "Missing or invalid siteuser_id" });
+  require SiteUsers;
+  my $siteuser = SiteUsers->getByPkey($siteuser_id)
+    or return $class->req_loclist($req, { siteuser_id => "Unknown siteuser_id" });
+
+  # make sure we got a valid seminar
+  require BSE::TB::Seminars;
+  my $seminar_id = $cgi->param('seminar_id');
+  defined $seminar_id && $seminar_id =~ /^\d*$/
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Missing or invalid seminar_id" });
+  $seminar_id
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Please select a seminar" });
+  my $seminar = BSE::TB::Seminars->getByPkey($seminar_id)
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Unknown seminar_id" });
+  my $msg = $req->message($errors);
+
+  my @sessions = $seminar->session_info;
+  my %user_booked = map { $_=>1 } 
+    $siteuser->seminar_sessions_booked($seminar_id);
+  @sessions = grep !$user_booked{$_->{id}}, @sessions;
+
+  my $it = BSE::Util::Iterate->new;
+  my %acts;
+  %acts =
+    (
+     BSE::Util::Tags->basic(\%acts, $req->cgi, $req->cfg),
+     BSE::Util::Tags->admin(\%acts, $req->cfg),
+     BSE::Util::Tags->secure($req),
+     siteuser => [ \&tag_hash, $siteuser ],
+     seminar => [ \&tag_hash, $seminar ],
+     msg => $msg,
+     message => $msg,
+     error_img => [ \&tag_error_img, $req->cfg, $errors ],
+     $it->make_iterator(undef, 'session', 'sessions', \@sessions),
+    );
+  
+  return $req->dyn_response('admin/addattendee2.tmpl', \%acts);
+}
+
+sub req_addattendsave {
+  my ($class, $req, $errors) = @_;
+
+  # make sure we're passed a valid siteuser_id
+  my $cgi = $req->cgi;
+  my $siteuser_id = $cgi->param('siteuser_id');
+  defined $siteuser_id && $siteuser_id =~ /^\d+$/
+    or return $class->req_loclist($req, { siteuser_id => 
+                                         "Missing or invalid siteuser_id" });
+  require SiteUsers;
+  my $siteuser = SiteUsers->getByPkey($siteuser_id)
+    or return $class->req_loclist($req, { siteuser_id => "Unknown siteuser_id" });
+
+  # make sure we got a valid seminar
+  require BSE::TB::Seminars;
+  my $seminar_id = $cgi->param('seminar_id');
+  defined $seminar_id && $seminar_id =~ /^\d*$/
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Missing or invalid seminar_id" });
+  $seminar_id
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Please select a seminar" });
+  my $seminar = BSE::TB::Seminars->getByPkey($seminar_id)
+    or return $class->req_addattendseminar
+      ($req, { seminar_id => "Unknown seminar_id" });
+  my $msg = $req->message($errors);
+
+  # make sure we get a valid session
+  require BSE::TB::SeminarSessions;
+  my $session_id = $cgi->param('session_id');
+  defined $session_id && $session_id =~ /^\d*$/
+    or return $class->req_addattendsession
+      ($req, { session_id => "Missing or invalid session_id" });
+  $session_id
+    or return $class->req_addattendsession
+      ($req, { session_id => "Please select a session" });
+  my $session = BSE::TB::SeminarSessions->getByPkey($session_id)
+    or return $class->req_addattendsession
+      ($req, { session_id => "Unknown session_id" });
+
+  eval {
+    $session->add_attendee($siteuser, 1);
+  };
+  if ($@) {
+    if ($@ =~ /duplicate/i) {
+      return $class->req_addattendsession
+       ($req, { session_id => "User already booked for this session" });
+    }
+  }
+
+  my $r = $cgi->param('r');
+  unless ($r) {
+    $r = "/cgi-bin/admin/siteusers.pl?a_edit=1&id=" . $siteuser->{id};
+  }
+  print STDERR "refresh $r\n";
+
+  return BSE::Template->get_refresh($r, $req->cfg);
+}
+
 1;
index 9d5aaef2eb80e35fdfafc8c3f6596780bd5a7a02..16df71f162f59f218a0416c02ad793a198f15b0d 100644 (file)
@@ -9,8 +9,9 @@ use BSE::CfgInfo qw(custom_class credit_card_class);
 use BSE::TB::Orders;
 use BSE::TB::OrderItems;
 use BSE::Mail;
-use BSE::Util::Tags qw(tag_error_img);
+use BSE::Util::Tags qw(tag_error_img tag_hash);
 use Products;
+use BSE::TB::Seminars;
 use DevHelp::Validate qw(dh_validate dh_validate_hash);
 use Digest::MD5 'md5_hex';
 
@@ -33,6 +34,7 @@ my %actions =
    show_payment => 1,
    payment => 1,
    orderdone => 1,
+   location => 1,
   );
 
 my %field_map = 
@@ -112,7 +114,10 @@ sub req_add {
   my $quantity = $cgi->param('quantity');
   $quantity ||= 1;
   my $product;
-  $product = Products->getByPkey($addid) if $addid;
+  if ($addid) {
+    $product = BSE::TB::Seminars->getByPkey($addid);
+    $product ||= Products->getByPkey($addid);
+  }
   $product or 
     return $class->req_cart($req, "Cannot find product $addid"); # oops
 
@@ -190,6 +195,34 @@ sub req_add {
   $quantity =~ /^\d+$/
     or return $class->req_cart($req, "Invalid quantity");
 
+  my %extras;
+  if ($product->isa('BSE::TB::Seminar')) {
+    # you must be logged on to add a seminar
+    unless ($user) {
+      return $class->_refresh_logon
+       ($req, "You must be logged on to add seminars to your cart", 
+        'seminarlogon', $r);
+    }
+
+    # get and validate the session
+    my $session_id = $cgi->param('session_id');
+    defined $session_id
+      or return $class->req_cart($req, "Please select a session when adding a seminar");
+    $session_id =~ /^\d+$/
+      or return $class->req_cart($req, "Invalid session_id supplied");
+    require BSE::TB::SeminarSessions;
+    my $session = BSE::TB::SeminarSessions->getByPkey($session_id)
+      or return $class->req_cart($req, "Unknown session id supplied");
+    $session->{seminar_id} == $addid
+      or return $class->req_cart($req, "Session not for this seminar");
+
+    # check if the user is already booked for this session
+    grep($_ == $session_id, $user->seminar_sessions_booked($addid))
+      and return $class->req_cart($req, "You are already booked for this session");
+
+    $extras{session_id} = $session_id;
+  }
+
   $req->session->{cart} ||= [];
   my @cart = @{$req->session->{cart}};
  
@@ -201,7 +234,8 @@ sub req_add {
      productId => $addid, 
      units => $quantity, 
      price=>$product->{retailPrice},
-     options=>$options 
+     options=>$options,
+     %extras,
     };
 
   $req->session->{cart} = \@cart;
@@ -571,6 +605,15 @@ sub req_payment {
     if ($sub) {
       $subscribing_to{$sub->{text_id}} = $sub;
     }
+
+    if ($item->{session_id}) {
+      my $user = $req->siteuser;
+      require BSE::TB::SeminarSessions;
+      my $session = BSE::TB::SeminarSessions->getByPkey($item->{session_id});
+      eval {
+       $session->add_attendee($user, 0);
+      };
+    }
   }
 
   $order->{ccOnline} = 0;
@@ -678,6 +721,10 @@ sub req_orderdone {
   my $item_index = -1;
   my @options;
   my $option_index;
+  my $item;
+  my $product;
+  my $sem_session;
+  my $location;
   my %acts;
   %acts =
     (
@@ -691,8 +738,16 @@ sub req_orderdone {
         $option_index = -1;
         @options = cart_item_opts($items[$item_index], 
                                   $products[$item_index]);
+        undef $sem_session;
+        undef $location;
+        $item = $items[$item_index];
+        $product = $products[$item_index];
         return 1;
        }
+       undef $item;
+       undef $sem_session;
+       undef $product;
+       undef $location;
        return 0;
      },
      item=> sub { escape_html($showitems[$item_index]{$_[0]}); },
@@ -732,6 +787,8 @@ sub req_orderdone {
      options => sub { nice_options(@options) },
      ifPayment => [ \&tag_ifPayment, $order->{paymentType}, \%types_by_name ],
      #ifSubscribingTo => [ \&tag_ifSubscribingTo, \%subscribing_to ],
+     session => [ \&tag_session, \$item, \$sem_session ],
+     location => [ \&tag_location, \$item, \$location ],
     );
   for my $type (@pay_types) {
     my $id = $type->{id};
@@ -742,6 +799,44 @@ sub req_orderdone {
   return $req->response('checkoutfinal', \%acts);
 }
 
+sub tag_session {
+  my ($ritem, $rsession, $arg) = @_;
+
+  $$ritem or return '';
+
+  $$ritem->{session_id} or return '';
+
+  unless ($$rsession) {
+    require BSE::TB::SeminarSessions;
+    $$rsession = BSE::TB::SeminarSessions->getByPkey($$ritem->{session_id})
+      or return '';
+  }
+
+  my $value = $$rsession->{$arg};
+  defined $value or return '';
+
+  escape_html($value);
+}
+
+sub tag_location {
+  my ($ritem, $rlocation, $arg) = @_;
+
+  $$ritem or return '';
+
+  $$ritem->{session_id} or return '';
+
+  unless ($$rlocation) {
+    require BSE::TB::Locations;
+    ($$rlocation) = BSE::TB::Locations->getSpecial(session_id => $$ritem->{session_id})
+      or return '';
+  }
+
+  my $value = $$rlocation->{$arg};
+  defined $value or return '';
+
+  escape_html($value);
+}
+
 sub tag_ifPayment {
   my ($payment, $types_by_name, $args) = @_;
 
@@ -1122,4 +1217,31 @@ sub _fillout_order {
 
 sub action_prefix { '' }
 
+sub req_location {
+  my ($class, $req) = @_;
+
+  require BSE::TB::Locations;
+  my $cgi = $req->cgi;
+  my $location_id = $cgi->param('location_id');
+  my $location;
+  if (defined $location_id && $location_id =~ /^\d$/) {
+    $location = BSE::TB::Locations->getByPkey($location_id);
+    my %acts;
+    %acts =
+      (
+       BSE::Util::Tags->static(\%acts, $req->cfg),
+       location => [ \&tag_hash, $location ],
+      );
+
+    return $req->response('location', \%acts);
+  }
+  else {
+    return
+      {
+       type=>BSE::Template->get_type($req->cfg, 'error'),
+       content=>"Missing or invalid location_id",
+      };
+  }
+}
+
 1;
index c761eb4f58b4df0f8ac83c77d0384e3d02b67a22..c050f4266724e35fc94872ba462c77787fd74b6c 100644 (file)
@@ -1,7 +1,8 @@
 package DevHelp::Date;
 use strict;
-use Exporter 'import';
-use vars qw(@EXPORT_OK %EXPORT_TAGS);
+require Exporter;
+use vars qw(@EXPORT_OK %EXPORT_TAGS @ISA);
+@ISA = qw(Exporter);
 @EXPORT_OK = 
   qw(dh_parse_date dh_parse_date_sql dh_parse_time dh_parse_time_sql);
 %EXPORT_TAGS =
index 7e3f90587a863f732dd954bc4de9b78b3ad406f0..68930d817d29a15a5928967a4b01840d09885cf6 100644 (file)
@@ -396,4 +396,11 @@ sub is_disabled {
   return $self->{disabled};
 }
 
+sub seminar_sessions_booked {
+  my ($self, $seminar_id) = @_;
+
+  return map $_->{session_id}, 
+    BSE::DB->query(userSeminarSessionBookings => $seminar_id, $self->{id});
+}
+
 1;
index f9e0e9bab148c890264ff04c1a6f15bebd228df2..6619947df4834fe5e15b541113c1b0791ab114f7 100755 (executable)
@@ -16,901 +16,6 @@ my $req = BSE::Request->new;
 my $result = BSE::UI::Shop->dispatch($req);
 BSE::Template->output_result($req, $result);
 
-
-
-# use Products;
-# use Product;
-# use Constants qw(:shop $CGI_URI);
-# use BSE::Template;
-# use CGI::Cookie;
-# use BSE::WebUtil qw(refresh_to);
-# use BSE::CfgInfo qw(custom_class);
-# use BSE::Mail;
-# use BSE::Shop::Util qw/shop_cart_tags cart_item_opts nice_options total 
-#                        basic_tags load_order_fields need_logon get_siteuser
-#                        payment_types/;
-# use BSE::Session;
-# use BSE::Cfg;
-# use BSE::Util::Tags qw(tag_hash);
-# use DevHelp::HTML;
-
-# my $cfg = BSE::Cfg->new();
-
-# my $subject = $cfg->entry('shop', 'subject', $SHOP_MAIL_SUBJECT);
-
-# # our PGP passphrase
-# my $passphrase = $SHOP_PASSPHRASE;
-
-# # the class we use to perform encryption
-# # we can change this to switch between GnuPG and PGP
-# my $crypto_class = $SHOP_CRYPTO;
-
-# # id of the private key to use for signing
-# # leave as undef to use your default key
-# my $signing_id = $SHOP_SIGNING_ID;
-
-# # location of PGP
-# my $pgpe = $SHOP_PGPE;
-# my $pgp = $SHOP_PGP;
-# my $gpg = $SHOP_GPG;
-
-# my $from = $cfg->entry('shop', 'from', $SHOP_FROM);
-
-# my $toName = $cfg->entry('shop', 'to_name', $SHOP_TO_NAME);
-# my $toEmail= $cfg->entry('shop', 'to_email', $SHOP_TO_EMAIL);
-
-# use constant PAYMENT_CC => 0;
-# use constant PAYMENT_CHEQUE => 1;
-# use constant PAYMENT_CALLME => 2;
-
-# my $urlbase = $cfg->entryVar('site', 'url');
-# my $securlbase = $cfg->entryVar('site', 'secureurl');
-# my %session;
-# BSE::Session->tie_it(\%session, $cfg);
-
-# # this shouldn't be necessary, but it stopped working elsewhere and this
-# # fixed it
-# END {
-#   untie %session;
-# }
-
-# if (!exists $session{cart}) {
-#   $session{cart} = [];
-# }
-
-# # the keys here are the names of the buttons on the various forms
-# # we also have 'delete_<number>' buttons.
-# my %steps =
-#   (
-#    add=>\&add_item,
-#    cart=>\&show_cart,
-#    checkout=>\&checkout,
-#    checkupdate => \&checkupdate,
-#    recheckout => sub { checkout('', 1); },
-#    confirm => \&checkout_confirm,
-#    recalc=>\&recalc,
-#    recalculate=>\&recalc,
-#    purchase=>\&purchase,
-#    #prePurchase=>\&prePurchase,
-#   );
-
-# for my $key (keys %steps) {
-#   if (param($key) or param("$key.x")) {
-#     $steps{$key}->();
-#     exit;
-#   }
-# }
-
-# for my $key (param()) {
-#   if ($key =~ /^delete_(\d+)/) {
-#     remove_item($1);
-#     exit;
-#   }
-# }
-
-# show_cart();
-
-# sub add_item {
-#   my $addid = param('id');
-#   $addid ||= '';
-#   my $quantity = param('quantity');
-#   $quantity ||= 1;
-#   my $product;
-#   $product = Products->getByPkey($addid) if $addid;
-#   $product or return show_cart("Cannot find product $addid"); # oops
-
-#   # collect the product options
-#   my @options;
-#   my @opt_names = split /,/, $product->{options};
-#   my @not_def;
-#   for my $name (@opt_names) {
-#     my $value = param($name);
-#     push @options, $value;
-#     unless (defined $value) {
-#       push @not_def, $name;
-#     }
-#   }
-#   @not_def
-#     and return show_cart("Some product options (@not_def) not supplied");
-#   my $options = join(",", @options);
-  
-#   # the product must be non-expired and listed
-#   use BSE::Util::SQL qw(now_sqldate);
-#   (my $comp_release = $product->{release}) =~ s/ .*//;
-#   (my $comp_expire = $product->{expire}) =~ s/ .*//;
-#   my $today = now_sqldate();
-#   $comp_release le $today
-#     or return show_cart("Product has not been released yet");
-#   $today le $comp_expire
-#     or return show_cart("Product has expired");
-#   $product->{listed} or return show_cart("Product not available");
-  
-#   # used to refresh if a logon is needed
-#   my $r = $securlbase . $ENV{SCRIPT_NAME} . "?add=1&id=$addid";
-#   for my $opt_index (0..$#opt_names) {
-#     $r .= "&$opt_names[$opt_index]=".escape_uri($options[$opt_index]);
-#   }
-  
-#   my $user = get_siteuser(\%session, $cfg, $CGI::Q);
-#   # need to be logged on if it has any subs
-#   if ($product->{subscription_id} != -1) {
-#     if ($user) {
-#       my $sub = $product->subscription;
-#       if ($product->is_renew_sub_only) {
-#      unless ($user->subscribed_to_grace($sub)) {
-#        return show_cart("This product can only be used to renew your subscription to $sub->{title} and you are not subscribed nor within the renewal grace period");
-#      }
-#       }
-#       elsif ($product->is_start_sub_only) {
-#      if ($user->subscribed_to_grace($sub)) {
-#        return show_cart("This product can only be used to start your subscription to $sub->{title} and you are already subscribed or within the grace period");
-#      }
-#       }
-#     }
-#     else {
-#       refresh_logon("You must be logged on to add this product to your cart",
-#                  'prodlogon', $r);
-#       return;
-#     }
-#   }
-#   if ($product->{subscription_required} != -1) {
-#     my $sub = $product->subscription_required;
-#     if ($user) {
-#       unless ($user->subscribed_to($sub)) {
-#      show_cart("You must be subscribed to $sub->{title} to purchase this product");
-#      return;
-#       }
-#     }
-#     else {
-#       # we want to refresh back to adding the item to the cart if possible
-#       refresh_logon("You must be logged on and subscribed to $sub->{title} to add this product to your cart",
-#                  'prodlogonsub', $r);
-#       return;
-#     }
-#   }
-
-#   # we need a natural integer quantity
-#   $quantity =~ /^\d+$/
-#     or return show_cart("Invalid quantity");
-
-#   my @cart = @{$session{cart}};
-#   # if this is is already present, replace it
-#   @cart = grep { $_->{productId} ne $addid || $_->{options} ne $options } 
-#     @cart;
-#   push(@cart, { productId => $addid, units => $quantity, 
-#              price=>$product->{retailPrice},
-#              options=>$options });
-
-#   $session{cart} = \@cart;
-#   show_cart();
-# }
-
-# sub show_cart {
-#   my ($msg) = @_;
-#   my @cart = @{$session{cart}};
-#   my @cart_prods = map { Products->getByPkey($_->{productId}) } @cart;
-#   my $item_index = -1;
-#   my @options;
-#   my $option_index;
-  
-#   $session{custom} ||= {};
-#   my %custom_state = %{$session{custom}};
-
-#   my $cust_class = custom_class($cfg);
-#   $cust_class->enter_cart(\@cart, \@cart_prods, \%custom_state, $cfg); 
-#   $msg = '' unless defined $msg;
-#   $msg = CGI::escapeHTML($msg);
-
-#   my %acts;
-#   %acts =
-#     (
-#      $cust_class->cart_actions(\%acts, \@cart, \@cart_prods, \%custom_state, 
-#                             $cfg),
-#      shop_cart_tags(\%acts, \@cart, \@cart_prods, \%session, $CGI::Q, $cfg,
-#                  'cart'),
-#      basic_tags(\%acts),
-#      msg => $msg,
-#     );
-#   $session{custom} = \%custom_state;
-
-#   page('cart.tmpl', \%acts);
-# }
-
-# sub update_quantities {
-#   my @cart = @{$session{cart}};
-#   for my $index (0..$#cart) {
-#     my $new_quantity = param("quantity_$index");
-#     if (defined $new_quantity) {
-#       if ($new_quantity =~ /^\s*(\d+)/) {
-#      $cart[$index]{units} = $1;
-#       }
-#       elsif ($new_quantity =~ /^\s*$/) {
-#      $cart[$index]{units} = 0;
-#       }
-#     }
-#   }
-#   @cart = grep { $_->{units} != 0 } @cart;
-#   $session{cart} = \@cart;
-#   $session{custom} ||= {};
-#   my %custom_state = %{$session{custom}};
-#   custom_class($cfg)->recalc($CGI::Q, \@cart, [], \%custom_state, $cfg);
-#   $session{custom} = \%custom_state;
-# }
-
-# sub recalc {
-#   update_quantities();
-#   show_cart();
-# }
-
-# sub remove_item {
-#   my ($index) = @_;
-#   my @cart = @{$session{cart}};
-#   if ($index >= 0 && $index < @cart) {
-#     splice(@cart, $index, 1);
-#   }
-#   $session{cart} = \@cart;
-
-#   refresh_to($ENV{SCRIPT_NAME});
-# }
-
-# sub checkupdate {
-#   my @cart = @{$session{cart}};
-#   my @cart_prods = map { Products->getByPkey($_->{productId}) } @cart;
-#   $session{custom} ||= {};
-#   my %custom_state = %{$session{custom}};
-#   custom_class($cfg)
-#       ->checkout_update($CGI::Q, \@cart, \@cart_prods, \%custom_state, $cfg);
-#   $session{custom} = \%custom_state;
-  
-#   checkout("", 1);
-# }
-
-# sub tag_checkedPayment {
-#   my ($payment, $types_by_name, $args) = @_;
-
-#   my $type = $args;
-#   if ($type !~ /^\d+$/) {
-#     return '' unless $types_by_name->{$type};
-#     $type = $types_by_name->{$type};
-#   }
-
-#   return $payment == $type  ? 'checked="checked"' : '';
-# }
-
-# sub tag_ifPayments {
-#   my ($enabled, $types_by_name, $args) = @_;
-
-#   my $type = $args;
-#   if ($type !~ /^\d+$/) {
-#     return '' unless $types_by_name->{$type};
-#     $type = $types_by_name->{$type};
-#   }
-
-#   my @found = grep $_ == $type, @$enabled;
-
-#   return scalar @found;
-# }
-
-# # display the checkout form
-# # can also be called with an error message and a flag to fillin the old
-# # values for the form elements
-# sub checkout {
-#   my ($message, $olddata) = @_;
-
-#   $message = '' unless defined $message;
-
-#   update_quantities();
-#   my @cart = @{$session{cart}};
-
-#   @cart or return show_cart();
-
-#   my @cart_prods = map { Products->getByPkey($_->{productId}) } @cart;
-
-#   if (my ($msg, $id) = need_logon($cfg, \@cart, \@cart_prods, \%session, $CGI::Q)) {
-#     refresh_logon($msg, $id);
-#     return;
-#   }
-
-#   my $user = get_siteuser(\%session, $cfg, $CGI::Q);
-
-#   $session{custom} ||= {};
-#   my %custom_state = %{$session{custom}};
-
-#   my $cust_class = custom_class($cfg);
-#   $cust_class->enter_cart(\@cart, \@cart_prods, \%custom_state, $cfg);
-
-#   my $noencrypt = $cfg->entryBool('shop', 'noencrypt', 0);
-
-#   my @pay_types = payment_types($cfg);
-#   my @payment_types = map $_->{id}, grep $_->{enabled}, @pay_types;
-#   my %types_by_name = map { $_->{name} => $_->{id} } @pay_types;
-#   if ($noencrypt) {
-#     @payment_types = grep $_ ne PAYMENT_CC, @payment_types;
-#     @payment_types or @payment_types = ( PAYMENT_CALLME );
-#   }
-#   else {
-#     @payment_types or @payment_types = ( PAYMENT_CC );
-#   }
-#   @payment_types = sort { $a <=> $b } @payment_types;
-#   my %payment_types = map { $_=> 1 } @payment_types;
-#   my $payment;
-#   $olddata and $payment = param('paymentType');
-#   defined $payment or $payment = $payment_types[0];
-
-#   my $affiliate_code = $session{affiliate_code};
-#   defined $affiliate_code or $affiliate_code = '';
-
-#   my $item_index = -1;
-#   my @options;
-#   my $option_index;
-#   my %acts;
-#   %acts =
-#     (
-#      shop_cart_tags(\%acts, \@cart, \@cart_prods, \%session, $CGI::Q, $cfg,
-#                 'checkout'),
-#      basic_tags(\%acts),
-#      message => sub { $message },
-#      old => 
-#      sub { 
-#        my $value;
-
-#        if ($olddata) {
-#       $value = param($_[0]);
-#       unless (defined $value) {
-#         $value = $user->{$_[0]}
-#           if $user;
-#       }
-#        }
-#        else {
-#       $value = $user && defined $user->{$_[0]} ? $user->{$_[0]} : '';
-#        }
-       
-#        defined $value or $value = '';
-#        CGI::escapeHTML($value);
-#      },
-#      $cust_class->checkout_actions(\%acts, \@cart, \@cart_prods, 
-#                                 \%custom_state, $CGI::Q, $cfg),
-#      ifMultPaymentTypes => @payment_types > 1,
-#      ifUser => defined $user,
-#      user => $user ? [ \&tag_hash, $user ] : '',
-#      checkedPayment => [ \&tag_checkedPayment, $payment, \%types_by_name ],
-#      ifPayments => [ \&tag_ifPayments, \@payment_types, \%types_by_name ],
-#      affiliate_code => escape_html($affiliate_code),
-#     );
-#   for my $type (@pay_types) {
-#     my $id = $type->{id};
-#     my $name = $type->{name};
-#     $acts{"if${name}Payments"} = exists $payment_types{$id};
-#     $acts{"if${name}FirstPayment"} = $payment_types[0] == $id;
-#     $acts{"checkedIfFirst$name"} = $payment_types[0] == $id ? "checked " : "";
-#     $acts{"checkedPayment$name"} = $payment == $id ? 'checked="checked" ' : "";
-#   }
-#   $session{custom} = \%custom_state;
-
-#   page('checkout.tmpl', \%acts);
-# }
-
-# # displays the data entered by the user so they can either confirm the
-# # details or redisplay the checkout page
-# sub checkout_confirm {
-#   my %order;
-#   my $error;
-
-#   my @cart_prods;
-#   unless (load_order_fields(0, $CGI::Q, \%order, \%session, \@cart_prods,
-#                             \$error)) {
-#     return checkout($error, 1);
-#   }
-#   ++$session{changed};
-#   my @cart = @{$session{cart}};
-#   # display the confirmation page
-#   my %acts;
-#   %acts =
-#     (
-#      order => sub { CGI::escapeHTML($order{$_[0]}) },
-#      shop_cart_tags(\%acts, \@cart, \@cart_prods, \%session, $CGI::Q, $cfg,
-#                  'confirm'),
-#      basic_tags(\%acts),
-#      old => 
-#      sub { 
-#        my $value = param($_[0]);
-#        defined $value or $value = '';
-#        CGI::escapeHTML($value);
-#      },
-#     );
-#   page('checkoutconfirm.tmpl', \%acts);
-# }
-
-# sub tag_ifPayment {
-#   my ($payment, $types_by_name, $args) = @_;
-
-#   my $type = $args;
-#   if ($type !~ /^\d+$/) {
-#     return '' unless $types_by_name->{$type};
-#     $type = $types_by_name->{$type};
-#   }
-
-#   return $payment == $type;
-# }
-
-# # the real work
-# sub purchase {
-#   $from && $from =~ /.\@./
-#     or return checkout("Configuration error: shop from address not set", 1);
-#   $toEmail && $toEmail =~ /.\@./
-#     or return checkout("Configuration error: shop to_email address not set", 1);
-
-#   # some basic validation, in case the user switched off javascript
-#   my $cust_class = custom_class($cfg);
-#   my @required = 
-#     $cust_class->required_fields($CGI::Q, $session{custom}, $cfg);
-
-#   my $noencrypt = $cfg->entryBool('shop', 'noencrypt', 0);
-
-#   my @pay_types = payment_types($cfg);
-#   my %pay_types = map { $_->{id} => $_ } @pay_types;
-#   my %types_by_name = map { $_->{name} => $_->{id} } @pay_types;
-#   #use Data::Dumper;
-#   #print STDERR Dumper \%pay_types;
-#   my @payment_types = map $_->{id}, grep $_->{enabled}, @pay_types;
-#   if ($noencrypt) {
-#     @payment_types = grep $_ ne PAYMENT_CC, @payment_types;
-#     @payment_types or @payment_types = ( PAYMENT_CALLME );
-#   }
-#   else {
-#     @payment_types or @payment_types = ( PAYMENT_CC );
-#   }
-#   @payment_types = sort { $a <=> $b } @payment_types;
-#   my %payment_types = map { $_=> 1 } @payment_types;
-
-#   my $paymentType = param('paymentType');
-#   defined $paymentType or $paymentType = $payment_types[0];
-#   $payment_types{$paymentType}
-#     or return checkout("Invalid payment type");
-
-#   push @required, @{$pay_types{$paymentType}{require}};
-
-#   for my $field (@required) {
-#     my $display = $cfg->entry('shop', "display_$field", $field);
-#     defined(param($field)) && length(param($field))
-#       or return checkout("Field $display is required", 1);
-#   }
-#   defined(param('email')) && param('email') =~ /.\@./
-#     or return checkout("Please enter a valid email address", 1);
-#   if ($paymentType == PAYMENT_CC) {
-#     defined(param('cardNumber')) && param('cardNumber') =~ /^\d+$/
-#       or return checkout("Please enter a credit card number", 1);
-#   }
-
-#   use BSE::TB::Orders;
-#   use BSE::TB::OrderItems;
-
-#   # map some form fields to order field names
-#   my %field_map = 
-#     (
-#      name1 => 'delivFirstName',
-#      name2 => 'delivLastName',
-#      address => 'delivStreet',
-#      city => 'delivSuburb',
-#      postcode => 'delivPostCode',
-#      state => 'delivState',
-#      country => 'delivCountry',
-#      email => 'emailAddress',
-#      cardHolder => 'ccName',
-#      cardType => 'ccType',
-#     );
-#   # paranoia, don't store these
-#   my %nostore =
-#     (
-#      cardNumber => 1,
-#      cardExpiry => 1,
-#     );
-#   my %order;
-#   my @cart = @{$session{cart}};
-#   @cart or return show_cart('You have no items in your shopping cart');
-
-#   # so we can quickly check for columns
-#   my @columns = BSE::TB::Order->columns;
-#   my %columns; 
-#   @columns{@columns} = @columns;
-
-#   for my $field (param()) {
-#     $order{$field_map{$field} || $field} = param($field)
-#       unless $nostore{$field};
-#   }
-
-#   my $ccNumber = param('cardNumber');
-#   defined $ccNumber or $ccNumber = '';
-#   my $ccExpiry = param('cardExpiry');
-#   defined $ccExpiry or $ccExpiry = '';
-#   my $affiliate_code = $session{affiliate_code};
-#   defined $affiliate_code && length $affiliate_code
-#     or $affiliate_code = param('affiliate_code');
-#   defined $affiliate_code or $affiliate_code = '';
-#   $order{affiliate_code} = $affiliate_code;
-
-#   use Digest::MD5 'md5_hex';
-#   $ccNumber =~ tr/0-9//cd;
-#   $order{ccNumberHash} = md5_hex($ccNumber);
-#   $order{ccExpiryHash} = md5_hex($ccExpiry);
-
-#   # work out totals
-#   $order{total} = 0;
-#   $order{gst} = 0;
-#   $order{wholesale} = 0;
-#   $order{shipping_cost} = 0;
-#   my @products;
-#   my $today = now_sqldate();
-#   for my $item (@cart) {
-#     my $product = Products->getByPkey($item->{productId});
-#     # double check that it's still a valid product
-#     if (!$product) {
-#       return show_cart("Product $item->{productId} not found");
-#     }
-#     else {
-#       (my $comp_release = $product->{release}) =~ s/ .*//;
-#       (my $comp_expire = $product->{expire}) =~ s/ .*//;
-#       $comp_release le $today
-#      or return show_cart("'$product->{title}' has not been released yet");
-#       $today le $comp_expire
-#      or return show_cart("'$product->{title}' has expired");
-#       $product->{listed} 
-#      or return show_cart("'$product->{title}' not available");
-#     }
-#     push(@products, $product); # used in page rendering
-#     @$item{qw/price wholesalePrice gst/} = 
-#       @$product{qw/retailPrice wholesalePrice gst/};
-#     $order{total} += $item->{price} * $item->{units};
-#     $order{wholesale} += $item->{wholesalePrice} * $item->{units};
-#     $order{gst} += $item->{gst} * $item->{units};
-#   }
-
-#   if (my ($msg, $id) = need_logon($cfg, \@cart, \@products, \%session, $CGI::Q)) {
-#     refresh_logon($msg, $id);
-#     return;
-#   }
-
-#   use BSE::Util::SQL qw(now_sqldatetime);
-#   $order{orderDate} = now_sqldatetime;
-#   $order{paymentType} = $paymentType;
-#   ++$session{changed};
-
-#   # blank anything else
-#   for my $column (@columns) {
-#     defined $order{$column} or $order{$column} = '';
-#   }
-#   # make sure the user can't set these behind our backs
-#   $order{filled} = 0;
-#   $order{paidFor} = 0;
-
-#   my $user = get_siteuser(\%session, $cfg, $CGI::Q);
-#   if ($user) {
-#     $order{userId} = $user->{userId};
-#     $order{siteuser_id} = $user->{id};
-#   }
-#   else {
-#     $order{userId} = '';
-#     $order{siteuser_id} = -1;
-#   }
-
-#   # this should be hard to guess
-#   $order{randomId} = md5_hex(time().rand().{}.$$);
-
-#   # check if a customizer has anything to do
-#   # if it sets shipping cost it must also update the total
-#   eval {
-#     my %custom = %{$session{custom}};
-#     $cust_class->order_save($CGI::Q, \%order, \@cart, \@products, 
-#                          \%custom, $cfg);
-#     $session{custom} = \%custom;
-#   };
-#   if ($@) {
-#     return checkout($@, 1);
-#   }
-
-#   $order{total} += $cust_class->total_extras(\@cart, \@products, 
-#                                           $session{custom}, $cfg, 'final');
-
-#   my %subscribing_to;
-
-#   # load up the database
-#   my @data = @order{@columns};
-#   shift @data; # lose the dummy id
-#   my $order = BSE::TB::Orders->add(@data)
-#     or die "Cannot add order";
-#   my @items;
-#   my @item_cols = BSE::TB::OrderItem->columns;
-#   my @prod_xfer = qw/title summary subscription_id subscription_period/;
-#   for my $row_num (0..$#cart) {
-#     my $row = $cart[$row_num];
-#     my $product = $products[$row_num];
-#     $row->{orderId} = $order->{id};
-
-#     # store product data too
-#     @$row{@prod_xfer} = @{$product}{@prod_xfer};
-
-#     # store the lapsed value, this prevents future changes causing
-#     # variation of the expiry date
-#     $row->{max_lapsed} = 0;
-#     if ($product->{subscription_id} != -1) {
-#       my $sub = $product->subscription;
-#       $row->{max_lapsed} = $sub->{max_lapsed} if $sub;
-#     }
-
-#     my @data = @$row{@item_cols};
-    
-#     shift @data;
-#     push(@items, BSE::TB::OrderItems->add(@data));
-
-#     my $sub = $product->subscription;
-#     if ($sub) {
-#       $subscribing_to{$sub->{text_id}} = $sub;
-#     }
-#   }
-
-#   if ($user) {
-#     $user->recalculate_subscriptions($cfg);
-#   }
-
-#   my $item_index = -1;
-#   my @options;
-#   my $option_index;
-#   my %acts;
-#   %acts =
-#     (
-#      $cust_class->purchase_actions(\%acts, \@items, \@products, 
-#                                 $session{custom}, $cfg),
-#      BSE::Util::Tags->static(\%acts, $cfg),
-#      iterate_items_reset => sub { $item_index = -1; },
-#      iterate_items => 
-#      sub { 
-#        if (++$item_index < @items) {
-#       $option_index = -1;
-#       @options = cart_item_opts($items[$item_index], 
-#                                 $products[$item_index]);
-#       return 1;
-#        }
-#        return 0;
-#      },
-#      item=> sub { CGI::escapeHTML($items[$item_index]{$_[0]}); },
-#      product => 
-#      sub { 
-#        my $value = $products[$item_index]{$_[0]};
-#        defined $value or $value = '';
-
-#        escape_html($value);
-#      },
-#      extended =>
-#      sub { 
-#        my $what = $_[0] || 'retailPrice';
-#        $items[$item_index]{units} * $items[$item_index]{$what};
-#      },
-#      order => sub { CGI::escapeHTML($order->{$_[0]}) },
-#      money =>
-#      sub {
-#        my ($func, $args) = split ' ', $_[0], 2;
-#        $acts{$func} || return "<: money $_[0] :>";
-#        return sprintf("%.02f", $acts{$func}->($args)/100);
-#      },
-#      _format =>
-#      sub {
-#        my ($value, $fmt) = @_;
-#        if ($fmt =~ /^m(\d+)/) {
-#       return sprintf("%$1s", sprintf("%.2f", $value/100));
-#        }
-#        elsif ($fmt =~ /%/) {
-#       return sprintf($fmt, $value);
-#        }
-#      },
-#      iterate_options_reset => sub { $option_index = -1 },
-#      iterate_options => sub { ++$option_index < @options },
-#      option => sub { CGI::escapeHTML($options[$option_index]{$_[0]}) },
-#      ifOptions => sub { @options },
-#      options => sub { nice_options(@options) },
-#      ifPayment => [ \&tag_ifPayment, $order->{paymentType}, \%types_by_name ],
-#      #ifSubscribingTo => [ \&tag_ifSubscribingTo, \%subscribing_to ],
-#     );
-#   for my $type (@pay_types) {
-#     my $id = $type->{id};
-#     my $name = $type->{name};
-#     $acts{"if${name}Payment"} = $order->{paymentType} == $id;
-#   }
-#   send_order($order, \@items, \@products, $noencrypt, \%subscribing_to);
-#   $session{cart} = []; # empty the cart
-#   page('checkoutfinal.tmpl', \%acts);
-# }
-
-# sub tag_ifSubscribingTo {
-#   my ($subscribing_to, $args) = @_;
-
-#   exists $subscribing_to->{$args};
-# }
-
-# sub tag_with_wrap {
-#   my ($args, $text) = @_;
-
-#   my $margin = $args =~ /^\d+$/ && $args > 30 ? $args : 70;
-
-#   require Text::Wrap;
-#   # do it twice to prevent a warning
-#   $Text::Wrap::columns = $margin;
-#   $Text::Wrap::columns = $margin;
-
-#   return Text::Wrap::fill('', '', split /\n/, $text);
-# }
-
-# # sends the email order confirmation and the PGP encrypted
-# # email to the site owner
-# sub send_order {
-#   my ($order, $items, $products, $noencrypt, $subscribing_to) = @_;
-
-#   my %extras = $cfg->entriesCS('extra tags');
-#   for my $key (keys %extras) {
-#     # follow any links
-#     my $data = $cfg->entryVar('extra tags', $key);
-#     $extras{$key} = sub { $data };
-#   }
-
-#   my $item_index = -1;
-#   my @options;
-#   my $option_index;
-#   my %acts;
-#   %acts =
-#     (
-#      %extras,
-#      custom_class($cfg)
-#      ->order_mail_actions(\%acts, $order, $items, $products, 
-#                        $session{custom}, $cfg),
-#      BSE::Util::Tags->static(\%acts, $cfg),
-#      iterate_items_reset => sub { $item_index = -1; },
-#      iterate_items => 
-#      sub { 
-#        if (++$item_index < @$items) {
-#       $option_index = -1;
-#       @options = cart_item_opts($items->[$item_index], 
-#                                 $products->[$item_index]);
-#       return 1;
-#        }
-#        return 0;
-#      },
-#      item=> sub { $items->[$item_index]{$_[0]}; },
-#      product => 
-#      sub { 
-#        my $value = $products->[$item_index]{$_[0]};
-#        defined($value) or $value = '';
-#        $value;
-#      },
-#      order => sub { $order->{$_[0]} },
-#      extended => 
-#      sub {
-#        $items->[$item_index]{units} * $items->[$item_index]{$_[0]};
-#      },
-#      _format =>
-#      sub {
-#        my ($value, $fmt) = @_;
-#        if ($fmt =~ /^m(\d+)/) {
-#       return sprintf("%$1s", sprintf("%.2f", $value/100));
-#        }
-#        elsif ($fmt =~ /%/) {
-#       return sprintf($fmt, $value);
-#        }
-#        elsif ($fmt =~ /^\d+$/) {
-#       return substr($value . (" " x $fmt), 0, $fmt);
-#        }
-#        else {
-#       return $value;
-#        }
-#      },
-#      iterate_options_reset => sub { $option_index = -1 },
-#      iterate_options => sub { ++$option_index < @options },
-#      option => sub { CGI::escapeHTML($options[$option_index]{$_[0]}) },
-#      ifOptions => sub { @options },
-#      options => sub { nice_options(@options) },
-#      with_wrap => \&tag_with_wrap,
-#      ifSubscribingTo => [ \&tag_ifSubscribingTo, $subscribing_to ],
-#     );
-
-#   my $mailer = BSE::Mail->new(cfg=>$cfg);
-#   # ok, send some email
-#   my $confirm = BSE::Template->get_page('mailconfirm', $cfg, \%acts);
-#   my $email_order = $cfg->entryBool('shop', 'email_order', $SHOP_EMAIL_ORDER);
-#   if ($email_order) {
-#     unless ($noencrypt) {
-#       $acts{cardNumber} = sub { param('cardNumber') };
-#       $acts{cardExpiry} = sub { param('cardExpiry') };
-#     }
-#     my $ordertext = BSE::Template->get_page('mailorder', $cfg, \%acts);
-    
-#     my $send_text;
-#     if ($noencrypt) {
-#       $send_text = $ordertext;
-#     }
-#     else {
-#       eval "use $crypto_class";
-#       !$@ or die $@;
-#       my $encrypter = $crypto_class->new;
-      
-#       my $debug = $cfg->entryBool('debug', 'mail_encryption', 0);
-#       my $sign = $cfg->entryBool('basic', 'sign', 1);
-      
-#       # encrypt and sign
-#       my %opts = 
-#      (
-#       sign=> $sign,
-#       passphrase=> $passphrase,
-#       stripwarn=>1,
-#       debug=>$debug,
-#      );
-      
-#       $opts{secretkeyid} = $signing_id if $signing_id;
-#       $opts{pgp} = $pgp if $pgp;
-#       $opts{gpg} = $gpg if $gpg;
-#       $opts{pgpe} = $pgpe if $pgpe;
-#       my $recip = "$toName $toEmail";
-
-#       $send_text = $encrypter->encrypt($recip, $ordertext, %opts )
-#      or die "Cannot encrypt ", $encrypter->error;
-#     }
-#     $mailer->send(to=>$toEmail, from=>$from, subject=>'New Order '.$order->{id},
-#                body=>$send_text)
-#       or print STDERR "Error sending order to admin: ",$mailer->errstr,"\n";
-#   }
-#   $mailer->send(to=>$order->{emailAddress}, from=>$from,
-#              subject=>$subject . " " . localtime,
-#              body=>$confirm)
-#     or print STDERR "Error sending order to customer: ",$mailer->errstr,"\n";
-# }
-
-# sub page {
-#   my ($template, $acts) = @_;
-
-#   BSE::Template->show_page($template, $cfg, $acts);
-# }
-
-# # convert an epoch time to sql format
-# sub epoch_to_sql {
-#   use POSIX 'strftime';
-#   my ($time) = @_;
-
-#   return strftime('%Y-%m-%d', localtime $time);
-# }
-
-# sub refresh_logon {
-#   my ($msg, $msgid, $r) = @_;
-#   my $url = $securlbase."/cgi-bin/user.pl";
-
-#   $r ||= $securlbase."/cgi-bin/shop.pl?checkout=1";
-  
-#   my %parms;
-#   $parms{r} = $r;
-#   $parms{message} = $msg if $msg;
-#   $parms{mid} = $msgid if $msgid;
-#   $url .= "?" . join("&", map "$_=".CGI::escape($parms{$_}), keys %parms);
-  
-#   refresh_to($url);
-# }
-
 __END__
 
 =head1 NAME
index 8bb2ee702520de1e1c5fcd8ce9c7c59c586a10b3..e6ff62984286da037403e6820ec64cb9953b5c8c 100644 (file)
@@ -10,6 +10,66 @@ Maybe I'll add some other bits here.
 
 =head1 CHANGES
 
+=head2 0.15_15
+
+=over
+
+=item *
+
+seminars can now be added to orders (if the user is logged on and
+isn't already booked)
+
+=item *
+
+added a_location target to shop.pl to display location information to
+end-users (intended for use as a pop-up)
+
+=item *
+
+removed old commented code from shop.pl
+
+=item *
+
+subs.pl now has normal admin tags on the newsletter list, including
+correcting the help tag.
+
+=item *
+
+the validation of the article parent id was incorrect, causing
+problems when saving existing articles.  Corrected the validation.
+
+=item *
+
+parsing and handling of the default value for the release and expire
+fields were reversed.
+
+=item *
+
+seminar display templates are now under the seminars directory
+
+=item *
+
+seminar display templates now have access to locations, location
+sessions and sessions iterators.
+
+=item *
+
+cart, checkoutnew and checkoutfinal templates now have access to
+per-item session and location tags
+
+=item *
+
+you can now add a user as a seminar attendee, without them having made
+an order.
+
+=item *
+
+DevHelp::Date had been changed to try to import its import method from
+Exporter, but this doesn't work on older perls.  Reverted to subclass
+Exporter.
+
+=back
+
 This is a development release, not intended for production.
 
 =head2 0.15_14
diff --git a/site/templates/admin/addattendee1.tmpl b/site/templates/admin/addattendee1.tmpl
new file mode 100644 (file)
index 0000000..1722641
--- /dev/null
@@ -0,0 +1,28 @@
+<:wrap admin/xbase.tmpl title=>"Add Seminar Attendee":>
+<h1>Add Seminar Attendee - Select a Seminar</h1>
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:> 
+<p>| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> 
+| <a href="<:script:>?id=<:siteuser id:>">Edit user</a> |
+</p>
+<p>Adding user <:siteuser userId:> as an attendee to:</p>
+<!-- leave this as get, since submitting it just displays a new page -->
+<form action="<:script:>" method="get" name="addattendee1">
+<input type="hidden" name="siteuser_id" value="<:siteuser id:>" />
+<:ifCgi r:><input type="hidden" name="r" value="<:cgi r:>" /><:or:><:eif:>
+<table>
+  <tr>
+    <th>Seminar:</th>
+    <td><select name="seminar_id">
+<option value="">(select a seminar)</option>
+<:iterator begin seminars:>
+<option value="<:seminar id:>" <:ifEq [old seminar_id] [seminar id]:>selected="selected"<:or:><:eif:>><:seminar title:> (<:seminar id:>)</option>
+<:iterator end seminars:>
+        </select></td>
+    <td><:error_img seminar_id:></td>
+  </tr>
+  <tr>
+    <td colspan="3"><input type="submit" name="a_addattendsession" value="Select Session &gt;&gt;" /></td>
+  </tr>
+</table>
diff --git a/site/templates/admin/addattendee2.tmpl b/site/templates/admin/addattendee2.tmpl
new file mode 100644 (file)
index 0000000..99b19a3
--- /dev/null
@@ -0,0 +1,33 @@
+<:wrap admin/xbase.tmpl title=>"Add Seminar Attendee":>
+<h1>Add Seminar Attendee - Select a Session</h1>
+<:ifMessage:>
+<p><b><:message:></b></p>
+<:or:><:eif:> 
+<p>| <a href="/cgi-bin/admin/menu.pl">Admin menu</a> | 
+<a href="<:script:>?id=<:siteuser id:>">Edit user</a> |
+</p>
+<p>Adding user <:siteuser userId:> as an attendee to:</p>
+<!-- leave this as get, since submitting it just displays a new page -->
+<form action="<:script:>" method="get" name="addattendee1">
+<input type="hidden" name="siteuser_id" value="<:siteuser id:>" />
+<input type="hidden" name="seminar_id" value="<:seminar id:>" />
+<:ifCgi r:><input type="hidden" name="r" value="<:cgi r:>" /><:or:><:eif:>
+<table>
+  <tr>
+    <th>Seminar:</th>
+    <td><:seminar title:></td>
+  </tr>
+  <tr>
+    <th>Session:</th>
+    <td><select name="session_id">
+<option value="">(select a session)</option>
+<:iterator begin sessions:>
+<option value="<:session id:>" <:ifEq [old session_id] [session id]:>selected="selected"<:or:><:eif:>><:session description:> <:date "%H:%M %d/%m/%Y" session when_at:></option>
+<:iterator end sessions:>
+        </select></td>
+    <td><:error_img session_id:></td>
+  </tr>
+  <tr>
+    <td colspan="3"><input type="submit" name="a_addattendsave" value="Select Session &gt;&gt;" /></td>
+  </tr>
+</table>
index a7506134a6b02cedcaff62b1a8972cc336c63a54..06ec178539a52fe941520c7b2a4a2bfbc0022b92 100644 (file)
@@ -4,7 +4,9 @@
 | <a href="/cgi-bin/admin/menu.pl">Admin menu</a> |
 <a href="/cgi-bin/admin/siteusers.pl">Site Members</a> |
 <a href="mailto:<:siteuser email:>">Email</a>
-<:ifUserorders:>| <a href="/cgi-bin/admin/siteusers.pl?a_edit=1&amp;id=<:siteuser id:>&amp;_t=orders">Orders</a><:or:><:eif:> |</p>
+<:ifUserorders:>| <a href="/cgi-bin/admin/siteusers.pl?a_edit=1&amp;id=<:siteuser id:>&amp;_t=orders">Orders</a><:or:><:eif:> |
+<a href="/cgi-bin/admin/admin_seminar.pl?a_addattendseminar=1&amp;siteuser_id=<:siteuser id:>">Add to seminar</a> |
+</p>
 
 <:ifMessage:>
 <p><b><:message:></b></p>
index 4b13dc8635065b6a2f20e471d31f866eddc116e6..264b4e3d0f916f6452141cef0f8b12e86e92aa95 100644 (file)
@@ -48,7 +48,7 @@
             <td width="100%" align="left"> &nbsp;<font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:item link:>"><:item 
               summary:> <:if Options:>(<:iterator begin options:><:option desc:>: 
               <:option label:><:iterator separator options:>, <:iterator end options:>)<:or 
-              Options:><:eif Options:></a></font></td>
+              Options:><:eif Options:></a><:ifItem session_id:>(session at <:location description:> <:date "%H:%M %d/%m/%Y" session when_at:>)<:or:><:eif:></font></td>
             <td nowrap align="center"> 
               <input type="text" name="quantity_<:index:>" size="2" value="<:item units:>">
             </td>
index af5737b24fc1f84bd45b83d4a042fc395b304b2d..a7f04ec0090f9981e9b8f0723c81c57f86621608 100644 (file)
@@ -58,8 +58,8 @@
         </tr>
         <:iterator begin items:> 
         <tr valign="middle" align="center" bgcolor="#FFFFFF"> 
-          <td width="100%" align="left"> &nbsp;<a href="<:product link:>"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><:product 
-            summary:> <:options:></font></a></td>
+          <td width="100%" align="left"> &nbsp;<font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:product link:>"><:product 
+            summary:></a> <:options:><:ifItem session_id:>(session at <:location description:> <:date "%H:%M %d/%m/%Y" session when_at:>)<:or:><:eif:></font></td>
           <td nowrap align="center"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><:item 
             units:></font></td>
           <td align="right"> <font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><b>$<: 
index 6c57f3e31ee151cdba631c6de58ea78504c3cf78..996b60ee35faa16838fab0fb623cfe0893d06bce 100644 (file)
@@ -85,8 +85,8 @@ function BSE_validateForm {
         </tr>
         <:iterator begin items:> 
         <tr valign="middle" align="center" bgcolor="#FFFFFF"> 
-          <td width="100%" align="left"> &nbsp;<a href="<:item link:>"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><:item 
-            summary:>  <:options:></font></a></td>
+          <td width="100%" align="left"> &nbsp;<font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><a href="<:item link:>"><:item 
+            summary:>  <:options:></a><:ifItem session_id:>(session at <:location description:> <:date "%H:%M %d/%m/%Y" session when_at:>)<:or:><:eif:></font></td>
           <td nowrap align="center"><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><:item 
             units:></font></td>
           <td align="right"> <font face="Verdana, Arial, Helvetica, sans-serif" size="-2"><b>$<: 
diff --git a/site/templates/location.tmpl b/site/templates/location.tmpl
new file mode 100644 (file)
index 0000000..963cb5a
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+  <head>
+    <title>Location: <:location description:></title>
+    <link rel="stylesheet" href="/css/admin.css">
+  </head>
+<body>
+<h1><:location description:></h1>
+<table>
+<tr><th>Address:</th>
+<td>
+<:ifLocation room:><:location room:><br /><:or:><:eif:>
+<:location street1:><br />
+<:ifLocation street2:><:location street2:><br /><:or:><:eif:>
+<:location suburb:> <:location state:> <:location postcode:>
+<:ifLocation country:><br /><:location country:><:or:><:eif:>
+</td></tr>
+<:if Location public_notes:>
+<tr>
+  <th>Notes</th>
+  <td><:bodytext location public_notes:></td>
+</tr>
+<:or Location:><:eif Location:>
+</table>
+</body></html>
\ No newline at end of file
diff --git a/site/templates/seminars/seminar.tmpl b/site/templates/seminars/seminar.tmpl
new file mode 100644 (file)
index 0000000..6929242
--- /dev/null
@@ -0,0 +1,169 @@
+ <:wrap base.tmpl:> <:embed start:><:admin:>
+<script>
+function show_location(locationid) {
+  window.open('/cgi-bin/shop.pl?a_location=1&amp;location_id='+locationid, 
+              'location', 
+              'width=600,height=300,location=no,status=no,menubar=no,scrollbars=yes');
+  return false;
+}
+</script>
+<table width="100%" border="0" cellspacing="0" cellpadding="0">
+  <tr> 
+    <td width="80%" height="24">&nbsp;&nbsp;<font face="Arial, Helvetica, sans-serif" size="4" color="#FF7F00"><b><:seminar 
+      title:></b></font></td>
+    <td height="24">&nbsp;</td>
+  </tr>
+  <tr> 
+    <td bgcolor="#999999" colspan="2" height="1"><img src="/images/trans_pixel.gif" width="24" height="1" border="0"></td>
+  </tr>
+  <tr> 
+    <td colspan="2"> 
+      <table width="100%" border="0" cellspacing="0" cellpadding="0">
+        <tr> 
+          <td width="100"><img src="/images/trans_pixel.gif" width="100" height="10" border="0"></td>
+          <td bgcolor="#999999" width="100%">&nbsp;<font face="Verdana, Arial, Helvetica, sans-serif" size="-2">/ 
+            <a href="<:ifAdmin:>/cgi-bin/admin/admin.pl?id=1<:or:>/<:eif:>"><font color="#FFFFFF">Home</font></a> 
+            / <:iterator begin crumbs:> <a href="<:url crumbs:>"><font color="#FFFFFF"><:crumbs 
+            title:></font></a> / <:iterator end crumbs:></font></td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+</table>
+<p><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><:body:></font></p>
+<:if StepCats:> <font face="Verdana, Arial, Helvetica, sans-serif" size="2">
+<p><b>Related categories:</b></p>
+<ul>
+<:iterator begin stepcats:>
+<li><a href="<:url stepcat:>"><:stepcat title:></a></li>
+<:iterator end stepcats:>
+</ul></font>
+<:or StepCats:><:eif StepCats:>
+<:if Product retailPrice:>
+<form name="ff" method="POST" action="/cgi-bin/shop.pl">
+<p><font face="Verdana, Arial, Helvetica, sans-serif" size="2">Select a seminar session to attend:</font></p>              
+     <:if Cfg seminar locations:>
+       <:iterator begin locations:>
+       <p><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><b><a href="/cgi-bin/shop.pl?a_location=1&amp;location_id=<:location id:>" onClick="return show_location(<:location id:>)"><:location description:></a></b></font></p>
+        <ul>
+         <:iterator begin location_sessions:>
+          <p><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><input type="radio" name="session_id" value="<:location_session id:>" /><:date "%H:%M %d/%m/%Y" location_session when_at:></font></p>
+         <:iterator end location_sessions:>
+        </ul>
+       <:iterator end locations:>
+     <:or Cfg:>
+       <:iterator begin sessions:>
+         <p><font face="Verdana, Arial, Helvetica, sans-serif" size="2"><input type="radio" name="session_id" value="<:session id:>" /><a href="/cgi-bin/shop.pl?a_location=1&amp;location_id=<:session location_id:>" onClick="return show_location(<:session location_id:>)"><:session description:></a> <:date "%H:%M %d/%m/%Y" session when_at:></font></p>
+       <:iterator end sessions:>
+     <:eif Cfg:>
+<:if Options:>
+  <table>
+<tr>
+       <:iterator begin options:><td valign="middle"> <font face="Verdana, Arial, Helvetica, sans-serif" size="2"><b><:option desc:>:</b></font></td><td> <:option popup:> </td><:iterator end options:>
+</tr>
+</table>
+  <:or Options:><:eif Options:>
+  <:ifProduct leadTime:> 
+   
+  <p><b><font face="Verdana, Arial, Helvetica, sans-serif" size="-2" color="#FE7F00">Usually ships in:</font><font face="Verdana, Arial, Helvetica, sans-serif" size="-2"> <:seminar leadTime:> <:if Eq [product leadTime] "1":>day<:or Eq:>days<:eif Eq:></font></b>
+</p>
+  <:or:><br><:eif:>
+
+<table border="0" cellspacing="0" cellpadding="0">
+    <tr valign="middle" align="center"> 
+      <td bgcolor="#666666"> 
+        <table width="100%" border="0" cellspacing="1" cellpadding="4" height="30">
+          <tr valign="middle" align="center"> 
+            <td bgcolor="#666666" align="left"> &nbsp;&nbsp;<font size="2" face="Verdana, Arial, Helvetica, sans-serif" color="#FFFFFF"> 
+              <b>Price:</b></font> &nbsp;&nbsp;</td>
+            <td bgcolor="#FFFFFF"> &nbsp; <font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#000000"> 
+              <b>$<:money product retailPrice:> </b>(inc GST)</font> </td>
+          </tr>
+        </table>
+      </td>
+      <td nowrap> &nbsp; 
+        <input type="hidden" name="id" value="<:seminar id:>">
+        <input type="hidden" name="quantity" value="1">
+        <input type="submit" name="add" value="Add to cart">
+        <input type="submit" name="cart" value="View cart">
+      </td>
+    </tr>
+  </table>
+</form>
+<:or Product:><br>
+<br>
+<table border="0" cellspacing="0" cellpadding="1" bgcolor="#CCCCCC">
+  <tr>
+    <td>
+      <table width="100%" border="0" cellspacing="0" cellpadding="10" bgcolor="#FFFFFF">
+        <tr> 
+          <td>
+            <form name="notifyme" method="post" action="/cgi-bin/interest.pl">
+              <font face="Arial, Helvetica, sans-serif" size="4"><b>Coming soon!</b></font> 
+              <input type="hidden" name="product" value="<:seminar title:>">
+              <p><font face="Verdana, Arial, Helvetica, sans-serif" size="-2">Yes, 
+                I want this product, notify me when it becomes available</font></p>
+              <table border="0" cellspacing="0" cellpadding="0">
+                <tr>
+                  <td><b><font face="Verdana, Arial, Helvetica, sans-serif" size="2"> 
+                    Email:</font></b>&nbsp;</td>
+                  <td>
+                    <input type="text" name="email" size="32">
+                    &nbsp; </td>
+                  <td> 
+                    <input type="submit" name="Submit" value="Notify me!">
+                  </td>
+                </tr>
+              </table>
+              </form>
+          </td>
+        </tr>
+      </table>
+    </td>
+  </tr>
+</table>
+<font face="Arial, Helvetica, sans-serif"><b><font size="4"> </font></b></font><:eif 
+Product:> 
+<p><br>
+  <a href="/shop/index.html"><img src="/images/store/browse_more.gif" width="133" height="21" border="0"></a>
+</p><br>
+<:if Files:> 
+<table border="0" cellspacing="0" cellpadding="0">
+  <tr> 
+    <td> 
+      <table border="0" cellspacing="0" cellpadding="4" bgcolor="#999999">
+        <tr> 
+          <th nowrap><font face="Verdana, Arial, Helvetica, sans-serif" size="2" color="#FFFFFF">&nbsp;&nbsp;Related 
+            file downloads&nbsp;&nbsp;</font></th>
+        </tr>
+      </table>
+    </td>
+  </tr>
+  <tr> 
+    <td bgcolor="#999999"> 
+      <table cellspacing="1" cellpadding="4">
+        <tr bgcolor="#CCCCCC"> 
+          <th><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif">Description</font></th>
+          <th><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif">Filename</font></th>
+          <th><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif">Size</font></th>
+          <th><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif">Status</font></th>
+        </tr>
+        <:iterator begin files:> 
+        <tr bgcolor="#FFFFFF"> 
+          <td bgcolor="#FFFFFF"><font font color="#000000" face="Verdana, Arial, Helvetica, sans-serif" size="-2"><:file 
+            description:></font></td>
+          <td bgcolor="#FFFFFF"><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif"><:if 
+            File forSale:><:file displayName:><:or File:><a href="/cgi-bin/user.pl?download_file=1&file=<:file id:><:ifFile requireUser:>&r=<:url article:><:or:><:eif:>"> 
+            <:file displayName:></a><:eif File:></font></td>
+          <td align="right"><font color="#000000" size="-2" face="Verdana, Arial, Helvetica, sans-serif"><:kb 
+            file sizeInBytes:></font></td>
+          <td nowrap align="center"> <:if File forSale:><img src="/images/filestatus/locked.gif" width="15" height="15" alt="Locked" title="Locked"><img src="/images/filestatus/forSale.gif" width="15" height="15" alt="File must be purchased" title="File must be purchased"><:or 
+            File:><a href="/cgi-bin/user.pl?download_file=1&file=<:file id:><:ifFile requireUser:>&r=<:url article:><:or:><:eif:>"><img src="/images/filestatus/download.gif" width="15" height="15" alt="Download now" title="Download now" border="0"></a><:ifFile 
+            requireUser:><img src="/images/filestatus/requireUser.gif" width="15" height="15" alt="For registered users only" title="For registered users only"><:or:><img src="/images/trans_pixel.gif" width="15" height="15" title="For registered users only"><:eif:><:eif 
+            File:></td>
+        </tr>
+        <:iterator end files:> </table>
+    </td>
+  </tr>
+</table>
+<:or Files:><:eif Files:><:embed end:>
\ No newline at end of file
index 203781b34c22f2d1bd079a1cf6345a2e0e25d2e7..52c60e70e04db5ffc2f12ae254e5c3ec6750b375 100644 (file)
@@ -40,7 +40,7 @@ middle of the previous paragraph.  Any other entry will abort.
 EOS
   my $entered = <STDIN>;
   chomp $entered;
-  if ($conf ne $conf) {
+  if ($entered ne $conf) {
     print "Either you didn't backup your data of you didn't read the message.\n";
     exit;
   }
@@ -112,6 +112,9 @@ for my $table (sort keys %tables) {
     for my $i (0..$#ccols) {
       my $col = $cols->[$i];
       my $ccol = $ccols[$i];
+      if ($ccol->{type} =~ /^varchar\((\d+)\) binary$/) {
+       $ccol->{type} = "varbinary($1)";
+      }
       defined $ccol->{default} or $ccol->{default} = 'NULL';
       
       $col->{field} eq $ccol->{field}
@@ -119,6 +122,12 @@ for my $table (sort keys %tables) {
       
       if ($col->{type} ne $ccol->{type} || $col->{default} ne $ccol->{default}) {
        print "fixing type or default for $col->{field}\n" if $verbose;
+       if ($verbose > 1) {
+         print "old type: $ccol->{type}  new type: $col->{type}\n"
+           if $ccol->{type} ne $col->{type};
+         print "old default: $ccol->{default}  new default: $col->{default}\n"
+           if $ccol->{default} ne $col->{default};
+       }
        my $sql = "alter table $table modify ".create_clauses($col);
        run_sql($sql)
          or die "Cannot fix $col->{field} type/default: $DBI::errstr\n";
index b1f629470d55c1eda0e902a216be06eb2f52e6bd..41477ecd09c6e676603777bb8aa3ddbc6255bf94 100644 (file)
--- a/test.cfg
+++ b/test.cfg
@@ -158,3 +158,5 @@ shop.cardprocessor=DevHelp::Payments::Test
 #inpho.test_password=test
 
 bse location validation.postcode_description=Funky Postcode
+
+seminar.locations=1