reverting to vendor branch rt 3.0.4, hopefully
[freeside.git] / rt / lib / RT / Transaction.pm
index ee1f069..ca491a6 100755 (executable)
-# $Header: /home/cvs/cvsroot/freeside/rt/lib/RT/Transaction.pm,v 1.1 2002-08-12 06:17:07 ivan Exp $
-# Copyright 1999-2001 Jesse Vincent <jesse@fsck.com>
-# Released under the terms of the GNU Public License
+# BEGIN LICENSE BLOCK
+# 
+# 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
+# Autogenerated by DBIx::SearchBuilder factory (by <jesse@bestpractical.com>)
+# WARNING: THIS FILE IS AUTOGENERATED. ALL CHANGES TO THIS FILE WILL BE LOST.  
+# 
+# !! DO NOT EDIT THIS FILE !!
+#
+
+use strict;
+
 
 =head1 NAME
 
-  RT::Transaction - RT\'s transaction object
+RT::Transaction
+
 
 =head1 SYNOPSIS
 
-  use RT::Transaction;
+=head1 DESCRIPTION
 
+=head1 METHODS
 
-=head1 DESCRIPTION
+=cut
 
+package RT::Transaction;
+use RT::Record; 
+use RT::Ticket;
 
-Each RT::Transaction describes an atomic change to a ticket object 
-or an update to an RT::Ticket object.
-It can have arbitrary MIME attachments.
 
+use vars qw( @ISA );
+@ISA= qw( RT::Record );
+
+sub _Init {
+  my $self = shift; 
+
+  $self->Table('Transactions');
+  $self->SUPER::_Init(@_);
+}
 
-=head1 METHODS
 
-=begin testing
 
-ok(require RT::TestHarness);
-ok(require RT::Transaction);
 
-=end testing
+
+=item Create PARAMHASH
+
+Create takes a hash of values and creates a row in the database:
+
+  int(11) 'EffectiveTicket'.
+  int(11) 'Ticket'.
+  int(11) 'TimeTaken'.
+  varchar(20) 'Type'.
+  varchar(40) 'Field'.
+  varchar(255) 'OldValue'.
+  varchar(255) 'NewValue'.
+  varchar(100) 'Data'.
 
 =cut
 
-package RT::Transaction;
 
-use RT::Record;
-@ISA= qw(RT::Record);
-    
-use RT::Attachments;
 
-# {{{ sub _Init 
-sub _Init  {
+
+sub Create {
     my $self = shift;
-  $self->{'table'} = "Transactions";
-  return ($self->SUPER::_Init(@_));
+    my %args = ( 
+                EffectiveTicket => '0',
+                Ticket => '0',
+                TimeTaken => '0',
+                Type => '',
+                Field => '',
+                OldValue => '',
+                NewValue => '',
+                Data => '',
+
+                 @_);
+    $self->SUPER::Create(
+                         EffectiveTicket => $args{'EffectiveTicket'},
+                         Ticket => $args{'Ticket'},
+                         TimeTaken => $args{'TimeTaken'},
+                         Type => $args{'Type'},
+                         Field => $args{'Field'},
+                         OldValue => $args{'OldValue'},
+                         NewValue => $args{'NewValue'},
+                         Data => $args{'Data'},
+);
 
 }
-# }}}
 
-# {{{ sub Create 
 
-=head2 Create
 
-Create a new transaction.
+=item id
 
-This routine should _never_ be called anything other Than RT::Ticket. It should not be called 
-from client code. Ever. Not ever.  If you do this, we will hunt you down. and break your kneecaps.
-Then the unpleasant stuff will start.
+Returns the current value of id. 
+(In the database, id is stored as int(11).)
 
-TODO: Document what gets passed to this
 
 =cut
 
-sub Create  {
-    my $self = shift;
-    my %args = ( id => undef,
-                TimeTaken => 0,
-                Ticket => 0 ,
-                Type => 'undefined',
-                Data => '',
-                Field => undef,
-                OldValue => undef,
-                NewValue => undef,
-                MIMEObj => undef,
-                ActivateScrips => 1,
-                @_
-              );
-    
-    #if we didn't specify a ticket, we need to bail
-    unless ( $args{'Ticket'} ) {
-       return(0, "RT::Transaction->Create couldn't, as you didn't specify a ticket id");
-    }
-        
-    #lets create our transaction
-    my $id = $self->SUPER::Create(Ticket => $args{'Ticket'},
-                                 TimeTaken => $args{'TimeTaken'},
-                                 Type => $args{'Type'},
-                                 Data => $args{'Data'},
-                                 Field => $args{'Field'},
-                                 OldValue => $args{'OldValue'},
-                                 NewValue => $args{'NewValue'},
-                                 Created => $args{'Created'}
-                                );
-    $self->Load($id);
-    $self->_Attach($args{'MIMEObj'})
-      if defined $args{'MIMEObj'};
-    
-    #Provide a way to turn off scrips if we need to
-    if ($args{'ActivateScrips'}) {
-
-       #We're really going to need a non-acled ticket for the scrips to work
-       my $TicketAsSystem = RT::Ticket->new($RT::SystemUser);
-       $TicketAsSystem->Load($args{'Ticket'}) || 
-         $RT::Logger->err("$self couldn't load ticket $args{'Ticket'}\n");
-       
-       my $TransAsSystem = RT::Transaction->new($RT::SystemUser);
-       $TransAsSystem->Load($self->id) ||
-         $RT::Logger->err("$self couldn't load a copy of itself as superuser\n");
-       
-       # {{{ Deal with Scrips
-    
-    #Load a scripscopes object
-    use RT::Scrips;
-    my $PossibleScrips = RT::Scrips->new($RT::SystemUser);
-    
-    $PossibleScrips->LimitToQueue($TicketAsSystem->QueueObj->Id); #Limit it to  $Ticket->QueueObj->Id
-    $PossibleScrips->LimitToGlobal(); # or to "global"
-    my $ConditionsAlias = $PossibleScrips->NewAlias('ScripConditions');
-    
-    $PossibleScrips->Join(ALIAS1 => 'main',  FIELD1 => 'ScripCondition',
-                         ALIAS2 => $ConditionsAlias, FIELD2=> 'id');
-    
-    
-    #We only want things where the scrip applies to this sort of transaction
-    $PossibleScrips->Limit(ALIAS=> $ConditionsAlias,
-                          FIELD=>'ApplicableTransTypes',
-                          OPERATOR => 'LIKE',
-                          VALUE => $args{'Type'},
-                          ENTRYAGGREGATOR => 'OR',
-                         );
-    
-    # Or where the scrip applies to any transaction
-    $PossibleScrips->Limit(ALIAS=> $ConditionsAlias,
-                          FIELD=>'ApplicableTransTypes',
-                          OPERATOR => 'LIKE',
-                          VALUE => "Any",
-                          ENTRYAGGREGATOR => 'OR',
-                         );                        
-    
-    #Iterate through each script and check it's applicability.
-    
-    while (my $Scrip = $PossibleScrips->Next()) {
-      
-      #TODO: properly deal with errors raised in this scrip loop
-       
-      #$RT::Logger->debug("$self now dealing with ".$Scrip->Id. "\n");      
-       eval {
-         local $SIG{__DIE__} = sub { $RT::Logger->error($_[0])};
-         
-         
-         #Load the scrip's Condition object
-         $Scrip->ConditionObj->LoadCondition(TicketObj => $TicketAsSystem, 
-                                             TransactionObj => $TransAsSystem);          
-         
-         
-         #If it's applicable, prepare and commit it
-         
-       $RT::Logger->debug ("$self: Checking condition ".$Scrip->ConditionObj->Name. "...\n");
-         
-         if ( $Scrip->IsApplicable() ) {
-             
-               $RT::Logger->debug ("$self: Matches condition ".$Scrip->ConditionObj->Name. "...\n");
-             #TODO: handle some errors here
-             
-             $Scrip->ActionObj->LoadAction(TicketObj => $TicketAsSystem, 
-                                          TransactionObj => $TransAsSystem);
-         
-             
-             if ($Scrip->Prepare()) {
-                 $RT::Logger->debug("$self: Prepared " .
-                                  $Scrip->ActionObj->Name . "\n");
-                 if ($Scrip->Commit()) {
-                       $RT::Logger->debug("$self: Committed " .
-                                          $Scrip->ActionObj->Name . "\n");
-                 }
-                 else {
-                       $RT::Logger->info("$self: Failed to commit ".
-                                          $Scrip->ActionObj->Name . "\n");
-                 } 
-             }
-             else {
-                 $RT::Logger->info("$self: Failed to prepare " .
-                                    $Scrip->ActionObj->Name . "\n");
-             }
-
-             #We're done with it. lets clean up.
-             #TODO: something else isn't letting these get garbage collected. check em out.
-             $Scrip->ActionObj->DESTROY();
-             $Scrip->ConditionObj->DESTROY;
-         }
-         
-         
-       else {
-           $RT::Logger->debug ("$self: Doesn't match condition ".$Scrip->ConditionObj->Name. "...\n");
-
-           # TODO: why doesn't this catch all the ScripObjs we create. 
-           # and why do we explictly need to destroy them?
-           $Scrip->ConditionObj->DESTROY;
-       }
-      }        
-    }
-
-    # }}}
-       
-    }
-
-    return ($id, "Transaction Created");
-}
 
-# }}}
+=item EffectiveTicket
 
-# {{{ sub Delete
+Returns the current value of EffectiveTicket. 
+(In the database, EffectiveTicket is stored as int(11).)
 
-sub Delete {
-    my $self = shift;
-    return (0, 'Deleting this object could break referential integrity');
-}
 
-# }}}
 
-# {{{ Routines dealing with Attachments
+=item SetEffectiveTicket VALUE
 
-# {{{ sub Message 
 
-=head2 Message
+Set EffectiveTicket to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, EffectiveTicket will be stored as a int(11).)
 
-  Returns the RT::Attachments Object which contains the "top-level" object
-  attachment for this transaction
 
 =cut
 
-sub Message  {
 
-    my $self = shift;
-    
-    if (!defined ($self->{'message'}) ){
-       
-       $self->{'message'} = new RT::Attachments($self->CurrentUser);
-       $self->{'message'}->Limit(FIELD => 'TransactionId',
-                                 VALUE => $self->Id);
-       
-       $self->{'message'}->ChildrenOf(0);
-    } 
-    return($self->{'message'});
-}
-# }}}
+=item Ticket
+
+Returns the current value of Ticket. 
+(In the database, Ticket is stored as int(11).)
+
 
-# {{{ sub Content
 
-=head2 Content PARAMHASH
+=item SetTicket VALUE
 
-If this transaction has attached mime objects, returns the first text/ part.
-Otherwise, returns undef.
 
-Takes a paramhash.  If the $args{'Quote'} parameter is set, wraps this message 
-at $args{'Wrap'}.  $args{'Wrap'} defaults to 70.
+Set Ticket to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Ticket will be stored as a int(11).)
 
 
 =cut
 
-sub Content {
-    my $self = shift;
-    my %args = ( Quote => 0,
-                Wrap => 70,
-                @_ );
-
-    my $content = undef;
-
-    # If we don\'t have any content, return undef now.
-    unless ($self->Message->First) {
-       return (undef);
-    }  
-    
-    # Get the set of toplevel attachments to this transaction.
-    my $MIMEObj = $self->Message->First();
-    
-    # If it's a message or a plain part, just return the
-    # body. 
-    if ($MIMEObj->ContentType() =~ '^(text|message)(/|$)') {
-       $content = $MIMEObj->Content();
-    }
-    
-    # If it's a multipart object, first try returning the first 
-    # text/plain part. 
-    
-    elsif ($MIMEObj->ContentType() =~ '^multipart/') {
-       my $plain_parts = $MIMEObj->Children();
-       $plain_parts->ContentType(VALUE => 'text/plain');
-       
-       # If we actully found a part, return its content
-       if ($plain_parts->First && 
-        $plain_parts->First->Content ne '') {
-           $content = $plain_parts->First->Content;            
-       }       
-       
-       # If that fails, return the  first text/ or message/ part 
-       # which has some content.
-    
-       else {
-           my $all_parts = $MIMEObj->Children();
-           while (($content == undef) && 
-                  (my $part = $all_parts->Next)) {
-               if (($part->ContentType() =~ '^(text|message)(/|$)') and
-                   ($part->Content())) {
-                   $content = $part->Content;
-               }       
-           }
-       }       
-
-    }
-    # If all else fails, return a message that we couldn't find
-    # any content
-    else { 
-        $content = 'This transaction appears to have no content';
-    }  
-
-    if ($args{'Quote'}) {
-       # Remove quoted signature.
-       $content =~ s/\n-- \n(.*)$//s;
-
-       # What's the longest line like?
-       foreach (split (/\n/,$content)) {
-           $max=length if ( length > $max);
-       }
-
-       if ($max>76) {
-           require Text::Wrapper;
-           my $wrapper=new Text::Wrapper
-               (
-                columns => $args{'Wrap'}, 
-                body_start => ($max > 70*3 ? '   ' : ''),
-                par_start => ''
-                );
-           $content=$wrapper->wrap($content);
-       }
-
-       $content =~ s/^/> /gm;
-       $content = '[' . $self->CreatorObj->Name() . ' - ' . $self->CreatedAsString()
-                   . "]:\n\n"
-               . $content . "\n\n";
-
-    }
-
-    return ($content); 
-}
-# }}}
 
-# {{{ sub Subject
+=item TicketObj
+
+Returns the Ticket Object which has the id returned by Ticket
 
-=head2 Subject
 
-If this transaction has attached mime objects, returns the first one's subject
-Otherwise, returns null
-  
 =cut
 
-sub Subject {
-    my $self = shift;
-    if ($self->Message->First) {
-       return ($self->Message->First->Subject);
-    }
-    else {
-       return (undef);
-    }
+sub TicketObj {
+       my $self = shift;
+       my $Ticket =  RT::Ticket->new($self->CurrentUser);
+       $Ticket->Load($self->__Value('Ticket'));
+       return($Ticket);
 }
-# }}}
 
-# {{{ sub Attachments 
+=item TimeTaken
+
+Returns the current value of TimeTaken. 
+(In the database, TimeTaken is stored as int(11).)
+
 
-=head2 Attachments
 
-  Returns all the RT::Attachment objects which are attached
-to this transaction. Takes an optional parameter, which is
-a ContentType that Attachments should be restricted to.
+=item SetTimeTaken VALUE
+
+
+Set TimeTaken to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, TimeTaken will be stored as a int(11).)
+
 
 =cut
 
 
-sub Attachments  {
-    my $self = shift;
-    my $Types = '';
-    $Types = shift if (@_);
-
-    my $Attachments = new RT::Attachments($self->CurrentUser);
-    
-    #If it's a comment, return an empty object if they don't have the right to see it
-    if ($self->Type eq 'Comment') {
-       unless ($self->CurrentUserHasRight('ShowTicketComments')) {
-           return ($Attachments);
-       }
-    }  
-    #if they ain't got rights to see, return an empty object
-    else {
-       unless ($self->CurrentUserHasRight('ShowTicket')) {
-           return ($Attachments);
-       }
-    }
-    
-    $Attachments->Limit(FIELD => 'TransactionId',
-                       VALUE => $self->Id);
-
-    # Get the attachments in the order they're put into
-    # the database.  Arguably, we should be returning a tree
-    # of attachments, not a set...but no current app seems to need
-    # it. 
-
-    $Attachments->OrderBy(ALIAS => 'main', 
-                         FIELD => 'Id',
-                         ORDER => 'asc');
-
-    if ($Types) {
-       $Attachments->ContentType( VALUE => "$Types",
-                                  OPERATOR => "LIKE");
-    }
-    
-    
-    return($Attachments);
-    
-}
+=item Type
 
-# }}}
+Returns the current value of Type. 
+(In the database, Type is stored as varchar(20).)
 
-# {{{ sub _Attach 
 
-=head2 _Attach
 
-A private method used to attach a mime object to this transaction.
+=item SetType VALUE
+
+
+Set Type to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Type will be stored as a varchar(20).)
+
 
 =cut
 
-sub _Attach  {
-    my $self = shift;
-    my $MIMEObject = shift;
-    
-    if (!defined($MIMEObject)) {
-       $RT::Logger->error("$self _Attach: We can't attach a mime object if you don't give us one.\n");
-       return(0, "$self: no attachment specified");
-    }
-    
-  
-    use RT::Attachment;
-    my $Attachment = new RT::Attachment ($self->CurrentUser);
-    $Attachment->Create(TransactionId => $self->Id,
-                       Attachment => $MIMEObject);
-    return ($Attachment, "Attachment created");
-    
-}
 
-# }}}
+=item Field
 
-# }}}
+Returns the current value of Field. 
+(In the database, Field is stored as varchar(40).)
 
-# {{{ Routines dealing with Transaction Attributes
 
-# {{{ sub TicketObj
 
-=head2 TicketObj
+=item SetField VALUE
+
+
+Set Field to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Field will be stored as a varchar(40).)
 
-Returns this transaction's ticket object.
 
 =cut
 
-sub TicketObj {
-    my $self = shift;
-    if (! exists $self->{'TicketObj'}) {
-       $self->{'TicketObj'} = new RT::Ticket($self->CurrentUser);
-       $self->{'TicketObj'}->Load($self->Ticket);
-    }
-    
-    return $self->{'TicketObj'};
-}
-# }}}
 
-# {{{ sub Description 
+=item OldValue
+
+Returns the current value of OldValue. 
+(In the database, OldValue is stored as varchar(255).)
+
+
+
+=item SetOldValue VALUE
+
 
-=head2 Description
+Set OldValue to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, OldValue will be stored as a varchar(255).)
 
-Returns a text string which describes this transaction
 
 =cut
 
 
-sub Description  {
-    my $self = shift;
+=item NewValue
+
+Returns the current value of NewValue. 
+(In the database, NewValue is stored as varchar(255).)
 
-    #Check those ACLs
-    #If it's a comment, we need to be extra special careful
-    if ($self->__Value('Type') eq 'Comment') {
-       unless ($self->CurrentUserHasRight('ShowTicketComments')) {
-           return (0, "Permission Denied");
-       }
-    }  
-
-    #if they ain't got rights to see, don't let em
-    else {
-       unless ($self->CurrentUserHasRight('ShowTicket')) {
-           return (0, "Permission Denied");
-       }
-    }
-
-    if (!defined($self->Type)) {
-       return("No transaction type specified");
-    }
-    
-    return ($self->BriefDescription . " by " . $self->CreatorObj->Name);
-}
 
-# }}}
 
-# {{{ sub BriefDescription 
+=item SetNewValue VALUE
 
-=head2 BriefDescription
 
-Returns a text string which briefly describes this transaction
+Set NewValue to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, NewValue will be stored as a varchar(255).)
+
 
 =cut
 
 
-sub BriefDescription  {
-    my $self = shift;
+=item Data
 
-    #Check those ACLs
-    #If it's a comment, we need to be extra special careful
-    if ($self->__Value('Type') eq 'Comment') {
-       unless ($self->CurrentUserHasRight('ShowTicketComments')) {
-           return (0, "Permission Denied");
-       }
-    }  
-
-    #if they ain't got rights to see, don't let em
-    else {
-       unless ($self->CurrentUserHasRight('ShowTicket')) {
-           return (0, "Permission Denied");
-       }
-    }
-
-    if (!defined($self->Type)) {
-       return("No transaction type specified");
-    }
-    
-    if ($self->Type eq 'Create'){
-       return("Ticket created");
-    }
-    elsif ($self->Type =~ /Status/) {
-       if ($self->Field eq 'Status') {
-           if ($self->NewValue eq 'dead') {
-               return ("Ticket killed");
-      }
-           else {
-               return( "Status changed from ".  $self->OldValue . 
-                       " to ". $self->NewValue);
-
-           }
-       }
-       # Generic:
-       return ($self->Field." changed from ".($self->OldValue||"(empty value)").
-         " to ".$self->NewValue );
-      }
-    
-    if ($self->Type eq 'Correspond')    {
-       return("Correspondence added");
-    }
-    
-    elsif ($self->Type eq 'Comment')  {
-       return( "Comments added");
-    }
-    
-    elsif ($self->Type eq 'Keyword') {
-
-       my $field = 'Keyword';
-
-       if ($self->Field) {
-           my $keywordsel = new RT::KeywordSelect ($self->CurrentUser);
-           $keywordsel->Load($self->Field);
-           $field = $keywordsel->Name();
-       }
-
-       if ($self->OldValue eq '') {
-           return ($field." ".$self->NewValue." added");
-       }
-       elsif ($self->NewValue eq '') {
-           return ($field." ".$self->OldValue." deleted"); 
-           
-       }
-       else {
-           return ($field." ".$self->OldValue . " changed to ". 
-                    $self->NewValue);
-       }       
-    }
-    
-    elsif ($self->Type eq 'Untake'){
-           return( "Untaken");
-       }
-    
-    elsif ($self->Type eq "Take") {
-       return( "Taken");
-    }
-    
-    elsif ($self->Type eq "Force") {
-        my $Old = RT::User->new($self->CurrentUser);
-        $Old->Load($self->OldValue);
-        my $New = RT::User->new($self->CurrentUser);
-        $New->Load($self->NewValue);
-       return "Owner forcibly changed from ".$Old->Name . " to ". $New->Name;
-    }
-    elsif ($self->Type eq "Steal") {
-       my $Old = RT::User->new($self->CurrentUser);
-       $Old->Load($self->OldValue);
-       return "Stolen from ".$Old->Name;
-    }
-    
-    elsif ($self->Type eq "Give") {
-       my $New = RT::User->new($self->CurrentUser);
-       $New->Load($self->NewValue);
-       return( "Given to ".$New->Name);
-    }
-    
-    elsif ($self->Type eq 'AddWatcher'){
-       return( $self->Field." ". $self->NewValue ." added");
-    }
-    
-    elsif ($self->Type eq 'DelWatcher'){
-       return( $self->Field." ".$self->OldValue ." deleted");
-    }
-    
-    elsif ($self->Type eq 'Subject') {
-       return( "Subject changed to ".$self->Data);
-    }
-    elsif ($self->Type eq 'Told') {
-       return( "User notified");
-    }
-    
-    elsif ($self->Type eq 'AddLink') {
-       return ($self->Data);
-    }
-    elsif ($self->Type eq 'DeleteLink') {
-       return ($self->Data);
-    }
-    elsif ($self->Type eq 'Set') {
-       if ($self->Field eq 'Queue') {
-           my $q1 = new RT::Queue($self->CurrentUser);
-           $q1->Load($self->OldValue);
-           my $q2 = new RT::Queue($self->CurrentUser);
-           $q2->Load($self->NewValue);
-           return ($self->Field . " changed from " . $q1->Name . " to ".
-                   $q2->Name);
-       }
-
-        # Write the date/time change at local time:                    
-    elsif ($self->Field =~  /Due|Starts|Started|Told/) {           
-        my $t1 = new RT::Date($self->CurrentUser);                 
-        $t1->Set(Format => 'ISO', Value => $self->NewValue);       
-        my $t2 = new RT::Date($self->CurrentUser);                 
-        $t2->Set(Format => 'ISO', Value => $self->OldValue);       
-        return ($self->Field . " changed from " . $t2->AsString .  
-                    " to ".$t1->AsString);      
-    }                
-       else {
-           return ($self->Field . " changed from " . $self->OldValue . 
-                   " to ".$self->NewValue);
-       }       
-    }
-    elsif ($self->Type eq 'PurgeTransaction') {
-       return ("Transaction ".$self->Data. " purged");
-    }
-    else {
-       return ("Default: ". $self->Type ."/". $self->Field . 
-               " changed from " . $self->OldValue . 
-               " to ".$self->NewValue);
-       
-    }
-}
+Returns the current value of Data. 
+(In the database, Data is stored as varchar(100).)
 
-# }}}
 
-# {{{ Utility methods
 
-# {{{ sub IsInbound
+=item SetData VALUE
 
-=head2 IsInbound
 
-Returns true if the creator of the transaction is a requestor of the ticket.
-Returns false otherwise
+Set Data to VALUE. 
+Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
+(In the database, Data will be stored as a varchar(100).)
 
-=cut
 
-sub IsInbound {
-    my $self=shift;
-    return ($self->TicketObj->IsRequestor($self->CreatorObj));
-}
+=cut
 
-# }}}
-
-# }}}
-
-# {{{ sub _Accessible 
-
-sub _Accessible  {
-  my $self = shift;
-  my %Cols = (
-             TimeTaken => 'read',
-             Ticket => 'read/public',
-             Type=> 'read',
-             Field => 'read',
-             Data => 'read',
-             NewValue => 'read',
-             OldValue => 'read',
-             Creator => 'read/auto',
-             Created => 'read/auto',
-            );
-  return $self->SUPER::_Accessible(@_, %Cols);
-}
 
-# }}}
+=item Creator
 
-# }}}
+Returns the current value of Creator. 
+(In the database, Creator is stored as int(11).)
 
-# {{{ sub _Set
 
-sub _Set {
-    my $self = shift;
-    return(0, 'Transactions are immutable');
-}
+=cut
 
-# }}}
 
-# {{{ sub _Value 
+=item Created
 
-=head2 _Value
+Returns the current value of Created. 
+(In the database, Created is stored as datetime.)
 
-Takes the name of a table column.
-Returns its value as a string, if the user passes an ACL check
 
 =cut
 
-sub _Value  {
 
-    my $self = shift;
-    my $field = shift;
-    
-    
-    #if the field is public, return it.
-    if ($self->_Accessible($field, 'public')) {
-       return($self->__Value($field));
-       
-    }
-    #If it's a comment, we need to be extra special careful
-    if ($self->__Value('Type') eq 'Comment') {
-       unless ($self->CurrentUserHasRight('ShowTicketComments')) {
-           return (undef);
-       }
-    }  
-    #if they ain't got rights to see, don't let em
-    else {
-       unless ($self->CurrentUserHasRight('ShowTicket')) {
-           return (undef);
-       }
-    }  
-    
-    return($self->__Value($field));
-    
-}
 
-# }}}
+sub _ClassAccessible {
+    {
+     
+        id =>
+               {read => 1, type => 'int(11)', default => ''},
+        EffectiveTicket => 
+               {read => 1, write => 1, type => 'int(11)', default => '0'},
+        Ticket => 
+               {read => 1, write => 1, type => 'int(11)', default => '0'},
+        TimeTaken => 
+               {read => 1, write => 1, type => 'int(11)', default => '0'},
+        Type => 
+               {read => 1, write => 1, type => 'varchar(20)', default => ''},
+        Field => 
+               {read => 1, write => 1, type => 'varchar(40)', default => ''},
+        OldValue => 
+               {read => 1, write => 1, type => 'varchar(255)', default => ''},
+        NewValue => 
+               {read => 1, write => 1, type => 'varchar(255)', default => ''},
+        Data => 
+               {read => 1, write => 1, type => 'varchar(100)', default => ''},
+        Creator => 
+               {read => 1, auto => 1, type => 'int(11)', default => '0'},
+        Created => 
+               {read => 1, auto => 1, type => 'datetime', default => ''},
 
-# {{{ sub CurrentUserHasRight
+ }
+};
 
-=head2 CurrentUserHasRight RIGHT
 
-Calls $self->CurrentUser->HasQueueRight for the right passed in here.
-passed in here.
+        eval "require RT::Transaction_Overlay";
+        if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Overlay.pm}) {
+            die $@;
+        };
 
-=cut
+        eval "require RT::Transaction_Vendor";
+        if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Vendor.pm}) {
+            die $@;
+        };
 
-sub CurrentUserHasRight {
-    my $self = shift;
-    my $right = shift;
-    return ($self->CurrentUser->HasQueueRight(Right => "$right", 
-                                              TicketObj => $self->TicketObj));            
-}
+        eval "require RT::Transaction_Local";
+        if ($@ && $@ !~ qr{^Can't locate RT/Transaction_Local.pm}) {
+            die $@;
+        };
+
+
+
+
+=head1 SEE ALSO
+
+This class allows "overlay" methods to be placed
+into the following files _Overlay is for a System overlay by the original author,
+_Vendor is for 3rd-party vendor add-ons, while _Local is for site-local customizations.  
+
+These overlay files can contain new subs or subs to replace existing subs in this module.
+
+If you'll be working with perl 5.6.0 or greater, each of these files should begin with the line 
+
+   no warnings qw(redefine);
+
+so that perl does not kick and scream when you redefine a subroutine or variable in your overlay.
+
+RT::Transaction_Overlay, RT::Transaction_Vendor, RT::Transaction_Local
+
+=cut
 
-# }}}
 
 1;