Reorganized RT->Freeside integration to support Internal (single RT/Freeside database...
authorkhoff <khoff>
Fri, 11 Mar 2005 01:34:31 +0000 (01:34 +0000)
committerkhoff <khoff>
Fri, 11 Mar 2005 01:34:31 +0000 (01:34 +0000)
All the UI stuff is handled the same either way.
Integration type is changed by setting $RT::URI::freeside::IntegrationType to either 'Internal' or 'XMLRPC' in your RT_SiteConfig.pm.

rt/etc/RT_SiteConfig.pm
rt/html/Elements/Header
rt/html/Elements/Menu
rt/html/Elements/Tabs
rt/html/Ticket/Elements/AddCustomers
rt/html/Ticket/Elements/ShowCustomers
rt/lib/RT/URI/freeside.pm
rt/lib/RT/URI/freeside/Internal.pm [new file with mode: 0644]
rt/lib/RT/URI/freeside/XMLRPC.pm [new file with mode: 0644]

index 572a2ba..3c37a41 100644 (file)
@@ -10,4 +10,6 @@ $RT::WebExternalAuth = 1;
 $RT::WebFallbackToInternal = 1; #no
 $RT::WebExternalAuto = 1;
 
+$RT::URI::freeside::IntegrationType = 'Internal';
+
 1;
index 27658df..4a16d56 100644 (file)
@@ -78,7 +78,7 @@ ONLOAD="
 <table width="100%" border="0" cellspacing="0" cellpadding="0" bgcolor="#FFFFFF">
   <tr> 
     <td rowspan=2><img border=0 alt="freeside" src="<%$RT::WebImagesURL%>/small-logo.png" width="92" height="62"></td>
-    <td align="left" rowspan=2><font size=6><% FS::Conf->new->config('company_name') %> Ticketing</font></td>
+    <td align="left" rowspan=2><font size=6><% &RT::URI::freeside::FreesideGetConfig('company_name') %> Ticketing</font></td>
     <td align="right" valign="top">
 % if ($session{'CurrentUser'} && $session{'CurrentUser'}->Id && $LoggedIn) {
 <SPAN STYLE="display: none"><A HREF="#skipnav"><&|/l&>Skip Menu</&></A> |</SPAN>
@@ -102,7 +102,7 @@ ONLOAD="
         <tr>
           <td align=right>
             <FONT SIZE="-3">
-              <A HREF="http://www.sisd.com/freeside">Freeside</A>&nbsp;v<% $FS::VERSION %><BR>
+              <A HREF="http://www.sisd.com/freeside">Freeside</A>&nbsp;v<% &RT::URI::freeside::FreesideVersion() %><BR>
              <A HREF="../docs/">Documentation</A><BR>
             </FONT>
           </td>
@@ -124,6 +124,7 @@ ONLOAD="
 
 $r->headers_out->{'Pragma'} = 'no-cache';
 $r->headers_out->{'Cache-control'} = 'no-cache';
+require RT::URI::freeside;
 </%INIT>
 
 <%ARGS>
index 0e57585..e933fb4 100644 (file)
@@ -78,7 +78,7 @@
 % } else {
 % $sep=0;
 % }
-<li style="<%$style%>"><A HREF="<%$RT::WebPath%>/<%$toptabs->{$tab}->{'path'}%>" style="font-size: <%$size%>;" class="<%$class%>" 
+<li style="<%$style%>"><A HREF="<% ($toptabs->{$tab}->{'path'} =~ /^http/) ? '' : "${RT::WebPath}/" %><%$toptabs->{$tab}->{'path'}%>" style="font-size: <%$size%>;" class="<%$class%>" 
 <%($class eq 'currenttopnav') ? "name='focus'" : ""|n %> 
 <% !$level && "accesskey='".$accesskey++."'" |n%>><% $toptabs->{$tab}->{'title'}%></A>
 %# Second-level items
index 4fc229b..4a018bf 100644 (file)
@@ -64,7 +64,7 @@ my $basetopactions = {
        };
 my $basetabs = {
                   ' A'=> { title => 'Billing Main',
-                           path  => '../',
+                           path  => &RT::URI::freeside::FreesideURL(),
                          },
                     A => { #title => loc('Homepage'),
                            title => 'Ticketing Main',
@@ -93,6 +93,8 @@ if (!defined $toptabs) {
 if (!defined $topactions) {
    $topactions = $basetopactions;
 }
+
+  require RT::URI::freeside;
                     
   # Now let callbacks add their extra tabs
   $m->comp('/Elements/Callback', 
index 66480e2..bfa6de9 100644 (file)
@@ -19,9 +19,8 @@
 % foreach my $customer (@Customers) {
 <tr>
   <td>
-    <input type="checkbox" name="Ticket-AddCustomer-<% $customer->custnum %>" VALUE="1" <% scalar(@Customers) == 1 ? 'CHECKED' : '' %>>
-%#    <% $customer->name %>
-    <A HREF="<% $p %>view/cust_main.cgi?<% $customer->custnum %>"><% small_custview( $customer, scalar(FS::Conf->new->config('countrydefault')), 1 ) |n %>
+    <input type="checkbox" name="Ticket-AddCustomer-<% $customer->{'custnum'} %>" VALUE="1" <% scalar(@Customers) == 1 ? 'CHECKED' : '' %>>
+    <A HREF="<%$freeside_url%>/view/cust_main.cgi?<% $customer->{'custnum'} %>"><% &RT::URI::freeside::small_custview($customer->{'custnum'}, &RT::URI::freeside::FreesideGetConfig('countrydefault'), 1) |n %>
   </td>
 </tr>
 % }
 <%INIT>
 my ($msg);
 
+my $freeside_url = &RT::URI::freeside::FreesideURL();
+
 my @Customers = ();
 if ( $CustomerString ) {
-    @Customers = smart_search( 'search' => $CustomerString );
+    @Customers = &RT::URI::freeside::smart_search( 'search' => $CustomerString );
     warn scalar(@Customers);
 }
 
@@ -42,9 +43,6 @@ if ($ServiceString) {
     @Services = (); #service_search();
 }
 
-eval { use FS::CGI qw( popurl small_custview ); };
-my $p = eval { popurl(3); };
-
 </%INIT>
 
 <%ARGS>
index 5519d24..612727e 100644 (file)
@@ -21,7 +21,7 @@
 %   my $cust_main = '';
   <tr>
     <td class="value">
-      <A HREF="<% $customerURI->Resolver->HREF %>"><% $customerURI->Resolver->AsStringLong |n %>
+      <A HREF="<% $customerURI->Resolver->HREF %>"><% $customerURI->Resolver->AsStringLong |n %></A>
     </td>
   </tr>
 % }
index ebd24ad..bd617f9 100644 (file)
@@ -28,143 +28,170 @@ package RT::URI::freeside;
 
 use RT::URI::base;
 use strict;
-use vars qw(@ISA);
-
+use vars qw(@ISA $IntegrationType);
 @ISA = qw/RT::URI::base/;
 
 
 =head1 NAME
 
-RT::URI::base
+RT::URI::freeside
 
 =head1 DESCRIPTION
 
 URI handler for freeside URIs.  See http://www.sisd.com/freeside/ for
 more information on freeside.
 
+
+=head1 Public subroutines
+
+=over 4
+
+=item FreesideGetConfig CONFKEY
+
+Subroutine that returns the freeside's configuration value(s) for CONFKEY
+as a scalar or list.
+
+=cut
+
+sub FreesideGetConfig { return undef; }
+
+
+=item FreesideURL
+
+Returns the URL for freeside's web interface.
+
+=cut
+
+sub FreesideURL { return undef; }
+
+
+=item FreesideVersion
+
+Returns a string describing the freeside version being used.
+
+=cut
+
+sub FreesideVersion { return undef; }
+
+
+=item smart_search
+
+A wrapper for the FS::cust_main::smart_search subroutine.
+
+=cut
+
+sub smart_search { return undef; }
+
+
+=item small_custview
+
+A wrapper for the FS::CGI::small_custview subroutine.
+
+=cut
+
+sub small_custview { return 'Freeside integration error!</A>'; }
+
+
+=back
+
+=head1 Private methods
+
+=over 4
+
+=item _FreesideGetRecord
+
+Method returns a hashref of the freeside record referenced in the URI.
+Must be called after ParseURI.
+
 =cut
 
+sub _FreesideGetRecord { return undef; }
 
-sub FreesideURIPrefix {
+
+=item _FreesideURIPrefix
+
+Method that returns the URI prefix for freeside URIs.
+
+=cut
+
+sub _FreesideURIPrefix {
 
   my $self = shift;
   return($self->Scheme . '://freeside');
 
 }
 
-sub FreesideURILabel {
+=item _FreesideURILabel
+
+Method that returns a short string describing the customer referenced
+in the URI.
+
+=cut
+
+sub _FreesideURILabel {
 
   my $self = shift;
 
-  return(undef) unless (exists($self->{'fstable'}) and
-                        exists($self->{'fspkey'}));
+  $RT::Logger->debug("Called _FreesideURILabel()");
+
+  return unless (exists($self->{'fstable'}) and
+                 exists($self->{'fspkey'}));
 
   my $label;
   my ($table, $pkey) = ($self->{'fstable'}, $self->{'fspkey'});
 
-  eval {
-    use FS::UID qw(dbh);
-    use FS::Record qw(qsearchs qsearch dbdef);
-    eval "use FS::$table;";
-    use FS::cust_svc;
-
-    my $dbdef = dbdef or die "No dbdef";
-    my $pkeyfield = $dbdef->table($table)->primary_key
-      or die "No primary key for table $table";
-
-    my $rec = qsearchs($table, { $pkeyfield => $pkey })
-      or die "Record with $pkeyfield == $pkey does not exist in table $table";
-
-    if ($table =~ /^svc_/) {
-      if ($rec->can('cust_svc')) {
-        my $cust_svc = $rec->cust_svc or die '$rec->cust_svc failed';
-        my ($svc, $tag, $svcdb) = $cust_svc->label;
-        $label = "Freeside service ${svc}: ${tag}";
-      }
-    } elsif ($table eq 'cust_main') {
-      #my ($last, $first, $company) = map { $rec->getfield($_) }
-      #                                   qw(last first company);
-      #$label = "Freeside customer ${last}, ${first}";
-      #$label .= ($company ne '') ? " with ${company}" : '';
-      $label = "$pkey: ". $rec->name;
-    } else {
-      $label = "Freeside ${table}, ${pkeyfield} == ${pkey}";
-    }
+  if ($table ne 'cust_main') {
+    warn "FS::${table} not currently supported";
+    return;
+  }
 
-    #... other cases
+  my $rec = $self->_FreesideGetRecord();
 
-  };
+  if (ref($rec) eq 'HASH' and $table eq 'cust_main') {
+    my $name = $rec->{'last'} . ', ' . $rec->{'first'};
+    $name = $rec->{'company'} . " ($name)" if $rec->{'company'};
+    $label = "$pkey: $name";
+  } else {
+    $label = "$pkey: $table";
+  }
 
   if ($label and !$@) {
     return($label);
   } else {
-    return(undef);
+    return;
   }
-      
 
 }
 
-sub FreesideURILabelLong {
+=item _FreesideURILabel
 
-  my $self = shift;
+Method that returns a longer string describing the customer referenced
+in the URI.
 
-  return(undef) unless (exists($self->{'fstable'}) and
-                        exists($self->{'fspkey'}));
+=cut
 
-  my $label;
-  my ($table, $pkey) = ($self->{'fstable'}, $self->{'fspkey'});
+sub _FreesideURILabelLong {
 
-  eval {
-    use FS::UID qw(dbh);
-    use FS::Record qw(qsearchs qsearch dbdef);
-    eval "use FS::$table;";
-    use FS::cust_svc;
-
-    my $dbdef = dbdef or die "No dbdef";
-    my $pkeyfield = $dbdef->table($table)->primary_key
-      or die "No primary key for table $table";
-
-    my $rec = qsearchs($table, { $pkeyfield => $pkey })
-      or die "Record with $pkeyfield == $pkey does not exist in table $table";
-
-    if ($table =~ /^svc_/) {
-      #if ($rec->can('cust_svc')) {
-      #  my $cust_svc = $rec->cust_svc or die '$rec->cust_svc failed';
-      #  my ($svc, $tag, $svcdb) = $cust_svc->label;
-      #  $label = "Freeside service ${svc}: ${tag}";
-      #}
-      $label = '';
-    } elsif ($table eq 'cust_main') {
-      use FS::CGI qw(small_custview);
-      $label = small_custview( $rec,
-                               scalar(FS::Conf->new->config('countrydefault')),
-                               1 #nobalance
-                             );
-    } else {
-      #$label = "Freeside ${table}, ${pkeyfield} == ${pkey}";
-      $label = '';
-    }
+  my $self = shift;
 
-    #... other cases
+  return $self->_FreesideURILabel();
 
-  };
+}
 
-  if ($label and !$@) {
-    return($label);
-  } else {
-    warn $@;
-    return(undef);
-  }
-      
+=back
 
-}
+=head1 Public methods
+
+=over 4
+
+=cut
 
 sub ParseURI { 
     my $self = shift;
     my $uri = shift;
     my ($table, $pkey);
 
-    my $uriprefix = $self->FreesideURIPrefix;
+    my $uriprefix = $self->_FreesideURIPrefix;
     if ($uri =~ /^$uriprefix\/(\w+)\/(\d+)$/) {
       $table = $1;
       $pkey = $2;
@@ -177,22 +204,13 @@ sub ParseURI {
     $self->{'fstable'} = $table;
     $self->{'fspkey'} = $pkey;
 
-    my $p;
-
-    eval {
-      use FS::UID qw(dbh);
-      use FS::CGI qw(popurl);
 
-      if (dbh) {
-       $p = popurl(3);
-      }
+    my $url = $self->FreesideURL();
 
-    };
-
-    if ($@ or (!$p)) {
-      $self->{'href'} = $self->{'uri'};
+    if ($url ne '') {
+      $self->{'href'} = "${url}/view/${table}.cgi?${pkey}";
     } else {
-      $self->{'href'} = "${p}view/${table}.cgi?${pkey}";
+      $self->{'href'} = $self->{'uri'};
     }
 
     $self->{'uri'};
@@ -215,7 +233,7 @@ sub IsLocal {
     return undef;
 }
 
-=head2 AsString
+=item AsString
 
 Return a "pretty" string representing the URI object.
 
@@ -229,14 +247,14 @@ This is meant to be used like this:
 sub AsString {
     my $self = shift;
     my $prettystring;
-    if ($prettystring = $self->FreesideURILabel) {
+    if ($prettystring = $self->_FreesideURILabel) {
       return $prettystring;
     } else {
       return $self->URI;
     }
 }
 
-=head2 AsStringLong
+=item AsStringLong
 
 Return a longer (HTML) string representing the URI object.
 
@@ -245,16 +263,23 @@ Return a longer (HTML) string representing the URI object.
 sub AsStringLong {
     my $self = shift;
     my $prettystring;
-    if ($prettystring = $self->FreesideURILabelLong || $self->FreesideURILabel){
+    if ($prettystring = $self->_FreesideURILabelLong || $self->_FreesideURILabel){
       return $prettystring;
     } else {
       return $self->URI;
     }
 }
 
-eval "require RT::URI::base_Vendor";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/URI/base_Vendor.pm});
-eval "require RT::URI::base_Local";
-die $@ if ($@ && $@ !~ qr{^Can't locate RT/URI/base_Local.pm});
+$IntegrationType ||= 'Internal';
+eval "require RT::URI::freeside::${RT::URI::freeside::IntegrationType}";
+warn $@ if $@;
+if ($@ &&
+    $@ !~ qr(^Can't locate RT/URI/freeside/${RT::URI::freeside::IntegrationType}.pm)) {
+  die $@;
+};
+
+=back
+
+=cut
 
 1;
diff --git a/rt/lib/RT/URI/freeside/Internal.pm b/rt/lib/RT/URI/freeside/Internal.pm
new file mode 100644 (file)
index 0000000..cdadd1e
--- /dev/null
@@ -0,0 +1,121 @@
+# BEGIN LICENSE BLOCK
+# 
+# Copyright (c) 2004 Kristian Hoffmann <khoff@fire2wire.com>
+# Based on the original RT::URI::base and RT::URI::fsck_com_rt.
+# 
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# 
+# (Except where explictly superceded by other copyright notices)
+# 
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+# 
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# Unless otherwise specified, all modifications, corrections or
+# extensions to this work which alter its source code become the
+# property of Best Practical Solutions, LLC when submitted for
+# inclusion in the work.
+# 
+# 
+# END LICENSE BLOCK
+#
+use strict;
+no warnings qw(redefine);
+
+use vars qw($conf);
+
+use FS;
+use FS::UID qw(dbh);
+use FS::CGI qw(popurl);
+use FS::Conf;
+use FS::Record qw(qsearchs qsearch dbdef);
+use FS::cust_main;
+use FS::cust_svc;
+
+=head1 NAME
+
+RT::URI::freeside::Internal
+
+=head1 DESCRIPTION
+
+Overlay for the RT::URI::freeside URI handler implementing the Internal integration type.
+
+See L<RT::URI::freeside> for public/private interface documentation.
+
+=cut
+
+
+
+sub _FreesideGetRecord {
+
+  my $self = shift;
+  my ($table, $pkey) = ($self->{'fstable'}, $self->{'fspkey'});
+
+  $RT::Logger->debug("Called _FreesideGetRecord()");
+
+  #eval "use FS::$table;";
+
+  my $dbdef = dbdef;
+  unless ($dbdef) {
+    $RT::Logger->error("Using Internal freeside integration type, ".
+                       "but it doesn't look like we're running under ".
+                       "freeside's Mason handler.");
+    return;
+  }
+
+  my $pkeyfield = $dbdef->table($table)->primary_key;
+  unless ($pkeyfield) {
+    $RT::Logger->error("No primary key for freeside table '$table'");
+    return;
+  }
+
+  my $fsrec = qsearchs($table, { $pkeyfield => $pkey });
+  unless ($fsrec) {
+    $RT::Logger->error("Record with '$pkeyfield' == '$pkey' does " .
+                       "not exist in table $table");
+    return;
+  }
+
+  return { $fsrec->hash };
+
+}
+
+sub FreesideURL {
+
+  return popurl(3);
+
+}
+
+sub FreesideVersion {
+
+  return $FS::VERSION;
+
+}
+
+sub FreesideGetConfig {
+
+  $conf = new FS::Conf unless ref($conf);
+
+  return $conf->config(@_);
+
+}
+
+sub smart_search { #Subroutine
+
+  return map { { $_->hash } } &FS::cust_main::smart_search(@_);
+
+}
+
+sub small_custview {
+
+  return &FS::CGI::small_custview(@_);
+
+}
+
+1;
diff --git a/rt/lib/RT/URI/freeside/XMLRPC.pm b/rt/lib/RT/URI/freeside/XMLRPC.pm
new file mode 100644 (file)
index 0000000..618364c
--- /dev/null
@@ -0,0 +1,128 @@
+# BEGIN LICENSE BLOCK
+# 
+# Copyright (c) 2004 Kristian Hoffmann <khoff@fire2wire.com>
+# Based on the original RT::URI::base and RT::URI::fsck_com_rt.
+# 
+# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+# 
+# (Except where explictly superceded by other copyright notices)
+# 
+# This work is made available to you under the terms of Version 2 of
+# the GNU General Public License. A copy of that license should have
+# been provided with this software, but in any event can be snarfed
+# from www.gnu.org.
+# 
+# This work is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+# 
+# Unless otherwise specified, all modifications, corrections or
+# extensions to this work which alter its source code become the
+# property of Best Practical Solutions, LLC when submitted for
+# inclusion in the work.
+# 
+# 
+# END LICENSE BLOCK
+
+use strict;
+no warnings qw(redefine);
+
+use vars qw($URL $XMLRPC_URL $_FS_VERSION);
+
+use Frontier::Client;
+
+=head1 NAME
+
+RT::URI::freeside::XMLRPC
+
+=head1 DESCRIPTION
+
+Overlay for the RT::URI::freeside URI handler implementing the XMLRPC integration type.
+
+See L<RT::URI::freeside> for public/private interface documentation.
+
+=cut
+
+
+sub _XMLRPCRequest { #Subroutine
+
+  my $method = shift;
+  my @args = @_;
+
+  my $result;
+  eval {
+    my $server = new Frontier::Client ( url => $XMLRPC_URL );
+    $result = $server->call($method, @args);
+  };
+
+  if (not $@ and ref($result) eq 'ARRAY') {
+    return (scalar(@$result) == 1) ? @$result[0] : @$result;
+  } else {
+    $RT::Logger->debug("Freeside XMLRPC: " . $result || $@);
+    return ();
+  }
+
+}
+
+sub _FreesideGetRecord {
+
+  my $self = shift;
+  my ($table, $pkey) = ($self->{'fstable'}, $self->{'fspkey'});
+  my $record;
+
+  $RT::Logger->debug("Called XMLRPC::_FreesideGetRecord()");
+
+  #FIXME: Need a better way to get primary keys.
+  # Maybe create a method for it and cache them like version?
+  my %table_pkeys = (
+    cust_main => 'custnum',
+  );
+    
+  my $method = 'Record.qsearchs';
+  my @args = ($table, { $table_pkeys{$table} => $pkey });
+  my ($record) = &_XMLRPCRequest($method, @args);
+
+  return $record;
+
+}
+
+
+sub FreesideGetConfig {
+
+  return _XMLRPCRequest('Conf.config', @_);
+
+}
+
+
+sub FreesideURL {
+
+  return $URL;
+
+}
+
+sub FreesideVersion {
+
+  return $_FS_VERSION if ($_FS_VERSION =~ /^\d+\.\d+\.\d+/);
+
+  $RT::Logger->debug("Requesting freeside version...");
+  ($_FS_VERSION) = &_XMLRPCRequest('version');
+  $RT::Logger->debug("Cached freeside version: ${_FS_VERSION}");
+  return $_FS_VERSION;
+
+}
+
+sub smart_search { #Subroutine
+
+  return _XMLRPCRequest('cust_main.smart_search', @_);
+
+}
+
+sub small_custview {
+
+  return _XMLRPCRequest('CGI.small_custview', @_);
+
+}
+
+1;