rt 4.0.23
[freeside.git] / rt / lib / RT / Ticket.pm
index de8a396..068eec0 100755 (executable)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
@@ -54,7 +54,7 @@
 
 =head1 DESCRIPTION
 
-This module lets you manipulate RT\'s ticket object.
+This module lets you manipulate RT's ticket object.
 
 
 =head1 METHODS
@@ -197,18 +197,18 @@ Arguments: ARGS is a hash of named parameters.  Valid parameters are:
   AdminCc  - A reference to a  list of  email addresses or Names
   SquelchMailTo - A reference to a list of email addresses - 
                   who should this ticket not mail
-  Type -- The ticket\'s type. ignore this for now
-  Owner -- This ticket\'s owner. either an RT::User object or this user\'s id
+  Type -- The ticket's type. ignore this for now
+  Owner -- This ticket's owner. either an RT::User object or this user's id
   Subject -- A string describing the subject of the ticket
   Priority -- an integer from 0 to 99
   InitialPriority -- an integer from 0 to 99
   FinalPriority -- an integer from 0 to 99
-  Status -- any valid status (Defined in RT::Queue)
+  Status -- any valid status for Queue's Lifecycle, otherwises uses on_create from Lifecycle default
   TimeEstimated -- an integer. estimated time for this task in minutes
   TimeWorked -- an integer. time worked so far in minutes
   TimeLeft -- an integer. time remaining in minutes
-  Starts -- an ISO date describing the ticket\'s start date and time in GMT
-  Due -- an ISO date describing the ticket\'s due date and time in GMT
+  Starts -- an ISO date describing the ticket's start date and time in GMT
+  Due -- an ISO date describing the ticket's due date and time in GMT
   MIMEObj -- a MIME::Entity object with the content of the initial ticket request.
   CustomField-<n> -- a scalar or array of values for the customfield with the id <n>
 
@@ -255,6 +255,7 @@ sub Create {
         Starts             => undef,
         Started            => undef,
         Resolved           => undef,
+        WillResolve        => undef,
         MIMEObj            => undef,
         _RecordTransaction => 1,
         DryRun             => 0,
@@ -299,6 +300,7 @@ sub Create {
         $args{'Status'} = $cycle->DefaultOnCreate;
     }
 
+    $args{'Status'} = lc $args{'Status'};
     unless ( $cycle->IsValid( $args{'Status'} ) ) {
         return ( 0, 0,
             $self->loc("Status '[_1]' isn't a valid status for tickets in this queue.",
@@ -356,6 +358,11 @@ sub Create {
         $Started->Set( Format => 'ISO', Value => $args{'Started'} );
     }
 
+    my $WillResolve = RT::Date->new($self->CurrentUser );
+    if ( defined $args{'WillResolve'} ) {
+        $WillResolve->Set( Format => 'ISO', Value => $args{'WillResolve'} );
+    }
+
     # If the status is not an initial status, set the started date
     elsif ( !$cycle->IsInitial($args{'Status'}) ) {
         $Started->SetToNow;
@@ -460,6 +467,11 @@ sub Create {
         }
     }
 
+    $args{'Type'} = lc $args{'Type'}
+        if $args{'Type'} =~ /^(ticket|approval|reminder)$/i;
+
+    $args{'Subject'} =~ s/\n//g;
+
     $RT::Handle->BeginTransaction();
 
     my %params = (
@@ -477,6 +489,7 @@ sub Create {
         Starts          => $Starts->ISO,
         Started         => $Started->ISO,
         Resolved        => $Resolved->ISO,
+        WillResolve     => $WillResolve->ISO,
         Due             => $Due->ISO
     );
 
@@ -629,7 +642,7 @@ sub Create {
                 }
             }
 
-            if ( $obj && $obj->Status eq 'deleted' ) {
+            if ( $obj && lc $obj->Status eq 'deleted' ) {
                 push @non_fatal_errors,
                   $self->loc("Linking. Can't link to a deleted ticket");
                 next;
@@ -783,6 +796,15 @@ sub Create {
     }
 }
 
+sub SetType {
+    my $self = shift;
+    my $value = shift;
+
+    # Force lowercase on internal RT types
+    $value = lc $value
+        if $value =~ /^(ticket|approval|reminder)$/i;
+    return $self->_Set(Field => 'Type', Value => $value, @_);
+}
 
 
 
@@ -836,10 +858,10 @@ sub _Parse822HeadersForAttributes {
         }
         $args{$date} = $dateobj->ISO;
     }
-    $args{'mimeobj'} = MIME::Entity->new();
-    $args{'mimeobj'}->build(
-        Type => ( $args{'contenttype'} || 'text/plain' ),
-        Data => ($args{'content'} || '')
+    $args{'mimeobj'} = MIME::Entity->build(
+        Type    => ( $args{'contenttype'} || 'text/plain' ),
+        Charset => "UTF-8",
+        Data    => Encode::encode("UTF-8", ($args{'content'} || ''))
     );
 
     return (%args);
@@ -850,8 +872,8 @@ sub _Parse822HeadersForAttributes {
 =head2 Import PARAMHASH
 
 Import a ticket. 
-Doesn\'t create a transaction. 
-Doesn\'t supply queue defaults, etc.
+Doesn't create a transaction. 
+Doesn't supply queue defaults, etc.
 
 Returns: TICKETID
 
@@ -885,7 +907,7 @@ sub Import {
         $QueueObj = RT::Queue->new(RT->SystemUser);
         $QueueObj->Load( $args{'Queue'} );
 
-        #TODO error check this and return 0 if it\'s not loading properly +++
+        #TODO error check this and return 0 if it's not loading properly +++
     }
     elsif ( ref( $args{'Queue'} ) eq 'RT::Queue' ) {
         $QueueObj = RT::Queue->new(RT->SystemUser);
@@ -1103,7 +1125,7 @@ PrincipalId The RT::Principal id of the user or group that's being added as a wa
 Email       The email address of the new watcher. If a user with this 
             email address can't be found, a new nonprivileged user will be created.
 
-If the watcher you\'re trying to set has an RT account, set the PrincipalId paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
+If the watcher you're trying to set has an RT account, set the PrincipalId paremeter to their User Id. Otherwise, set the Email parameter to their Email address.
 
 =cut
 
@@ -1124,7 +1146,7 @@ sub AddWatcher {
         return (0, $self->loc("Couldn't parse address from '[_1]' string", $args{'Email'} ))
             unless $addr;
 
-        if ( lc $self->CurrentUser->UserObj->EmailAddress
+        if ( lc $self->CurrentUser->EmailAddress
             eq lc RT::User->CanonicalizeEmailAddress( $addr->address ) )
         {
             $args{'PrincipalId'} = $self->CurrentUser->id;
@@ -1206,7 +1228,8 @@ sub _AddWatcher {
 
     if ( $group->HasMember( $principal)) {
 
-        return ( 0, $self->loc('That principal is already a [_1] for this ticket', $self->loc($args{'Type'})) );
+        return ( 0, $self->loc('[_1] is already a [_2] for this ticket',
+                    $principal->Object->Name, $self->loc($args{'Type'})) );
     }
 
 
@@ -1215,7 +1238,8 @@ sub _AddWatcher {
     unless ($m_id) {
         $RT::Logger->error("Failed to add ".$principal->Id." as a member of group ".$group->Id.": ".$m_msg);
 
-        return ( 0, $self->loc('Could not make that principal a [_1] for this ticket', $self->loc($args{'Type'})) );
+        return ( 0, $self->loc('Could not make [_1] a [_2] for this ticket',
+                    $principal->Object->Name, $self->loc($args{'Type'})) );
     }
 
     unless ( $args{'Silent'} ) {
@@ -1226,7 +1250,8 @@ sub _AddWatcher {
         );
     }
 
-        return ( 1, $self->loc('Added principal as a [_1] for this ticket', $self->loc($args{'Type'})) );
+    return ( 1, $self->loc('Added [_1] as a [_2] for this ticket',
+                $principal->Object->Name, $self->loc($args{'Type'})) );
 }
 
 
@@ -1305,7 +1330,7 @@ sub DeleteWatcher {
             }
         }
         else {
-            $RT::Logger->warn("$self -> DeleteWatcher got passed a bogus type");
+            $RT::Logger->warning("$self -> DeleteWatcher got passed a bogus type");
             return ( 0,
                      $self->loc('Error in parameters to Ticket->DeleteWatcher') );
         }
@@ -1325,8 +1350,8 @@ sub DeleteWatcher {
 
     unless ( $group->HasMember($principal) ) {
         return ( 0,
-                 $self->loc( 'That principal is not a [_1] for this ticket',
-                             $args{'Type'} ) );
+                 $self->loc( '[_1] is not a [_2] for this ticket',
+                             $principal->Object->Name, $args{'Type'} ) );
     }
 
     my ( $m_id, $m_msg ) = $group->_DeleteMember( $principal->Id );
@@ -1339,8 +1364,8 @@ sub DeleteWatcher {
 
         return (0,
                 $self->loc(
-                    'Could not remove that principal as a [_1] for this ticket',
-                    $args{'Type'} ) );
+                    'Could not remove [_1] as a [_2] for this ticket',
+                    $principal->Object->Name, $args{'Type'} ) );
     }
 
     unless ( $args{'Silent'} ) {
@@ -1421,7 +1446,7 @@ sub UnsquelchMailTo {
 
 =head2 RequestorAddresses
 
- B<Returns> String: All Ticket Requestor email addresses as a string.
+B<Returns> String: All Ticket Requestor email addresses as a string.
 
 =cut
 
@@ -1794,7 +1819,7 @@ sub SetQueue {
         unless ( $old_lifecycle->HasMoveMap( $new_lifecycle ) ) {
             return ( 0, $self->loc("There is no mapping for statuses between these queues. Contact your system administrator.") );
         }
-        $new_status = $old_lifecycle->MoveMap( $new_lifecycle )->{ $self->Status };
+        $new_status = $old_lifecycle->MoveMap( $new_lifecycle )->{ lc $self->Status };
         return ( 0, $self->loc("Mapping between queues' lifecycles is incomplete. Contact your system administrator.") )
             unless $new_status;
     }
@@ -1891,6 +1916,13 @@ sub QueueObj {
     return ($self->{_queue_obj});
 }
 
+sub SetSubject {
+    my $self = shift;
+    my $value = shift;
+    $value =~ s/\n//g;
+    return $self->_Set( Field => 'Subject', Value => $value );
+}
+
 =head2 SubjectTag
 
 Takes nothing. Returns SubjectTag for this ticket. Includes
@@ -1989,6 +2021,31 @@ sub FirstActiveStatus {
     return $next;
 }
 
+=head2 FirstInactiveStatus
+
+Returns the first inactive status that the ticket could transition to,
+according to its current Queue's lifecycle.  May return undef if there
+is no such possible status to transition to, or we are already in it.
+This is used in resolve action in UnsafeEmailCommands, for instance.
+
+=cut
+
+sub FirstInactiveStatus {
+    my $self = shift;
+
+    my $lifecycle = $self->QueueObj->Lifecycle;
+    my $status = $self->Status;
+    my @inactive = $lifecycle->Inactive;
+    # no change if no inactive statuses in the lifecycle
+    return undef unless @inactive;
+
+    # no change if the ticket is already has first status from the list of inactive
+    return undef if lc $status eq lc $inactive[0];
+
+    my ($next) = grep $lifecycle->IsInactive($_), $lifecycle->Transitions($status);
+    return $next;
+}
+
 =head2 SetStarted
 
 Takes a date in ISO format or undef
@@ -2174,14 +2231,16 @@ sub Comment {
     }
     $args{'NoteType'} = 'Comment';
 
+    $RT::Handle->BeginTransaction();
     if ($args{'DryRun'}) {
-        $RT::Handle->BeginTransaction();
         $args{'CommitScrips'} = 0;
     }
 
     my @results = $self->_RecordNote(%args);
     if ($args{'DryRun'}) {
         $RT::Handle->Rollback();
+    } else {
+        $RT::Handle->Commit();
     }
 
     return(@results);
@@ -2220,15 +2279,20 @@ sub Correspond {
              or ( $self->CurrentUserHasRight('ModifyTicket') ) ) {
         return ( 0, $self->loc("Permission Denied"), undef );
     }
+    $args{'NoteType'} = 'Correspond';
 
-    $args{'NoteType'} = 'Correspond'; 
+    $RT::Handle->BeginTransaction();
     if ($args{'DryRun'}) {
-        $RT::Handle->BeginTransaction();
         $args{'CommitScrips'} = 0;
     }
 
     my @results = $self->_RecordNote(%args);
 
+    unless ( $results[0] ) {
+        $RT::Handle->Rollback();
+        return @results;
+    }
+
     #Set the last told date to now if this isn't mail from the requestor.
     #TODO: Note that this will wrongly ack mail from any non-requestor as a "told"
     unless ( $self->IsRequestor($self->CurrentUser->id) ) {
@@ -2240,6 +2304,8 @@ sub Correspond {
 
     if ($args{'DryRun'}) {
         $RT::Handle->Rollback();
+    } else {
+        $RT::Handle->Commit();
     }
 
     return (@results);
@@ -2278,11 +2344,17 @@ sub _RecordNote {
     }
 
     unless ( $args{'MIMEObj'} ) {
+        my $data = ref $args{'Content'}? $args{'Content'} : [ $args{'Content'} ];
         $args{'MIMEObj'} = MIME::Entity->build(
-            Data => ( ref $args{'Content'}? $args{'Content'}: [ $args{'Content'} ] )
+            Type    => "text/plain",
+            Charset => "UTF-8",
+            Data    => [ map {Encode::encode("UTF-8", $_)} @{$data} ],
         );
     }
 
+    $args{'MIMEObj'}->head->replace('X-RT-Interface' => 'API')
+        unless $args{'MIMEObj'}->head->get('X-RT-Interface');
+
     # convert text parts into utf-8
     RT::I18N::SetMIMEEntityToUTF8( $args{'MIMEObj'} );
 
@@ -2298,13 +2370,13 @@ sub _RecordNote {
             my $addresses = join ', ', (
                 map { RT::User->CanonicalizeEmailAddress( $_->address ) }
                     Email::Address->parse( $args{ $type . 'MessageTo' } ) );
-            $args{'MIMEObj'}->head->replace( 'RT-Send-' . $type, Encode::encode_utf8( $addresses ) );
+            $args{'MIMEObj'}->head->replace( 'RT-Send-' . $type, Encode::encode( "UTF-8", $addresses ) );
         }
     }
 
     foreach my $argument (qw(Encrypt Sign)) {
         $args{'MIMEObj'}->head->replace(
-            "X-RT-$argument" => Encode::encode_utf8( $args{ $argument } )
+            "X-RT-$argument" => Encode::encode( "UTF-8", $args{ $argument } )
         ) if defined $args{ $argument };
     }
 
@@ -2312,17 +2384,19 @@ sub _RecordNote {
     # internal Message-ID now, so all emails sent because of this
     # message have a common Message-ID
     my $org = RT->Config->Get('Organization');
-    my $msgid = $args{'MIMEObj'}->head->get('Message-ID');
+    my $msgid = Encode::decode( "UTF-8", $args{'MIMEObj'}->head->get('Message-ID') );
     unless (defined $msgid && $msgid =~ /<(rt-.*?-\d+-\d+)\.(\d+-0-0)\@\Q$org\E>/) {
         $args{'MIMEObj'}->head->set(
-            'RT-Message-ID' => RT::Interface::Email::GenMessageId( Ticket => $self )
+            'RT-Message-ID' => Encode::encode( "UTF-8",
+                RT::Interface::Email::GenMessageId( Ticket => $self )
+            )
         );
     }
 
     #Record the correspondence (write the transaction)
     my ( $Trans, $msg, $TransObj ) = $self->_NewTransaction(
              Type => $args{'NoteType'},
-             Data => ( $args{'MIMEObj'}->head->get('subject') || 'No Subject' ),
+             Data => ( Encode::decode( "UTF-8", $args{'MIMEObj'}->head->get('Subject') ) || 'No Subject' ),
              TimeTaken => $args{'TimeTaken'},
              MIMEObj   => $args{'MIMEObj'}, 
              CommitScrips => $args{'CommitScrips'},
@@ -2358,10 +2432,10 @@ sub DryRun {
     }
 
     my $Message = MIME::Entity->build(
+        Subject => defined $args{UpdateSubject} ? Encode::encode( "UTF-8", $args{UpdateSubject} ) : "",
         Type    => 'text/plain',
-        Subject => defined $args{UpdateSubject} ? Encode::encode_utf8( $args{UpdateSubject} ) : "",
         Charset => 'UTF-8',
-        Data    => $args{'UpdateContent'} || "",
+        Data    => Encode::encode("UTF-8", $args{'UpdateContent'} || ""),
     );
 
     my ( $Transaction, $Description, $Object ) = $self->$action(
@@ -2390,12 +2464,12 @@ sub DryRunCreate {
     my $self = shift;
     my %args = @_;
     my $Message = MIME::Entity->build(
-        Type    => 'text/plain',
-        Subject => defined $args{Subject} ? Encode::encode_utf8( $args{'Subject'} ) : "",
+        Subject => defined $args{Subject} ? Encode::encode( "UTF-8", $args{'Subject'} ) : "",
         (defined $args{'Cc'} ?
-             ( Cc => Encode::encode_utf8( $args{'Cc'} ) ) : ()),
+             ( Cc => Encode::encode( "UTF-8", $args{'Cc'} ) ) : ()),
+        Type    => 'text/plain',
         Charset => 'UTF-8',
-        Data    => $args{'Content'} || "",
+        Data    => Encode::encode( "UTF-8", $args{'Content'} || ""),
     );
 
     my ( $Transaction, $Object, $Description ) = $self->Create(
@@ -2443,16 +2517,18 @@ sub _Links {
     }
 
     # Maybe this ticket is a merge ticket
-    my $limit_on = 'Local'. $field;
+    #my $limit_on = 'Local'. $field;
     # at least to myself
     $links->Limit(
-        FIELD           => $limit_on,
-        VALUE           => $self->id,
+        FIELD           => $field, #$limit_on,
+        OPERATOR        => 'MATCHES',
+        VALUE           => 'fsck.com-rt://%/ticket/'. $self->id,
         ENTRYAGGREGATOR => 'OR',
     );
     $links->Limit(
-        FIELD           => $limit_on,
-        VALUE           => $_,
+        FIELD           => $field, #$limit_on,
+        OPERATOR        => 'MATCHES',
+        VALUE           => 'fsck.com-rt://%/ticket/'. $_,
         ENTRYAGGREGATOR => 'OR',
     ) foreach $self->Merged;
     $links->Limit(
@@ -2469,7 +2545,7 @@ sub _Links {
 
 Delete a link. takes a paramhash of Base, Target, Type, Silent,
 SilentBase and SilentTarget. Either Base or Target must be null.
-The null value will be replaced with this ticket\'s id.
+The null value will be replaced with this ticket's id.
 
 If Silent is true then no transaction would be recorded, in other
 case you can control creation of transactions on both base and
@@ -2608,7 +2684,7 @@ sub AddLink {
     }
 
     return ( 0, "Can't link to a deleted ticket" )
-      if $other_ticket && $other_ticket->Status eq 'deleted';
+      if $other_ticket && lc $other_ticket->Status eq 'deleted';
 
     return $self->_AddLink(%args);
 }
@@ -2620,9 +2696,7 @@ sub __GetTicketFromURI {
     # If the other URI is an RT::Ticket, we want to make sure the user
     # can modify it too...
     my $uri_obj = RT::URI->new( $self->CurrentUser );
-    $uri_obj->FromURI( $args{'URI'} );
-
-    unless ( $uri_obj->Resolver && $uri_obj->Scheme ) {
+    unless ($uri_obj->FromURI( $args{'URI'} )) {
         my $msg = $self->loc( "Couldn't resolve '[_1]' into a URI.", $args{'URI'} );
         $RT::Logger->warning( $msg );
         return( 0, $msg );
@@ -3163,11 +3237,16 @@ sub ValidateStatus {
     return 0;
 }
 
-
+sub Status {
+    my $self = shift;
+    my $value = $self->_Value( 'Status' );
+    return $value unless $self->QueueObj;
+    return $self->QueueObj->Lifecycle->CanonicalCase( $value );
+}
 
 =head2 SetStatus STATUS
 
-Set this ticket\'s status. STATUS can be one of: new, open, stalled, resolved, rejected or deleted.
+Set this ticket's status. STATUS can be one of: new, open, stalled, resolved, rejected or deleted.
 
 Alternatively, you can pass in a list of named parameters (Status => STATUS, Force => FORCE, SetStarted => SETSTARTED ).
 If FORCE is true, ignore unresolved dependencies and force a status change.
@@ -3193,7 +3272,7 @@ sub SetStatus {
 
     my $lifecycle = $self->QueueObj->Lifecycle;
 
-    my $new = $args{'Status'};
+    my $new = lc $args{'Status'};
     unless ( $lifecycle->IsValid( $new ) ) {
         return (0, $self->loc("Status '[_1]' isn't a valid status for tickets in this queue.", $self->loc($new)));
     }
@@ -3241,7 +3320,7 @@ sub SetStatus {
     #Actually update the status
     my ($val, $msg)= $self->_Set(
         Field           => 'Status',
-        Value           => $args{Status},
+        Value           => $new,
         TimeTaken       => 0,
         CheckACL        => 0,
         TransactionType => 'Status',
@@ -3338,6 +3417,28 @@ sub SeenUpTo {
     return $txns->First;
 }
 
+=head2 RanTransactionBatch
+
+Acts as a guard around running TransactionBatch scrips.
+
+Should be false until you enter the code that runs TransactionBatch scrips
+
+Accepts an optional argument to indicate that TransactionBatch Scrips should no longer be run on this object.
+
+=cut
+
+sub RanTransactionBatch {
+    my $self = shift;
+    my $val = shift;
+
+    if ( defined $val ) {
+        return $self->{_RanTransactionBatch} = $val;
+    } else {
+        return $self->{_RanTransactionBatch};
+    }
+
+}
+
 
 =head2 TransactionBatch
 
@@ -3374,6 +3475,22 @@ sub ApplyTransactionBatch {
 
 sub _ApplyTransactionBatch {
     my $self = shift;
+
+    return if $self->RanTransactionBatch;
+    $self->RanTransactionBatch(1);
+
+    my $still_exists = RT::Ticket->new( RT->SystemUser );
+    $still_exists->Load( $self->Id );
+    if (not $still_exists->Id) {
+        # The ticket has been removed from the database, but we still
+        # have pending TransactionBatch txns for it.  Unfortunately,
+        # because it isn't in the DB anymore, attempting to run scrips
+        # on it may produce unpredictable results; simply drop the
+        # batched transactions.
+        $RT::Logger->warning("TransactionBatch was fired on a ticket that no longer exists; unable to run scrips!  Call ->ApplyTransactionBatch before shredding the ticket, for consistent results.");
+        return;
+    }
+
     my $batch = $self->TransactionBatch;
 
     my %seen;
@@ -3421,10 +3538,7 @@ sub DESTROY {
         return;
     }
 
-    my $batch = $self->TransactionBatch;
-    return unless $batch && @$batch;
-
-    return $self->_ApplyTransactionBatch;
+    return $self->ApplyTransactionBatch;
 }
 
 
@@ -3510,6 +3624,9 @@ sub _Set {
                                                OldValue  => $Old,
                                                TimeTaken => $args{'TimeTaken'},
         );
+        # Ensure that we can read the transaction, even if the change
+        # just made the ticket unreadable to us
+        $TransObj->{ _object_is_readable } = 1;
         return ( $Trans, scalar $TransObj->BriefDescription );
     }
     else {
@@ -3722,37 +3839,29 @@ sub TransactionCustomFields {
 }
 
 
+=head2 LoadCustomFieldByIdentifier
 
-=head2 CustomFieldValues
-
-# Do name => id mapping (if needed) before falling back to
-# RT::Record's CustomFieldValues
-
-See L<RT::Record>
+Finds and returns the custom field of the given name for the ticket,
+overriding L<RT::Record/LoadCustomFieldByIdentifier> to look for
+queue-specific CFs before global ones.
 
 =cut
 
-sub CustomFieldValues {
+sub LoadCustomFieldByIdentifier {
     my $self  = shift;
     my $field = shift;
 
-    return $self->SUPER::CustomFieldValues( $field ) if !$field || $field =~ /^\d+$/;
+    return $self->SUPER::LoadCustomFieldByIdentifier($field)
+        if ref $field or $field =~ /^\d+$/;
 
     my $cf = RT::CustomField->new( $self->CurrentUser );
     $cf->SetContextObject( $self );
     $cf->LoadByNameAndQueue( Name => $field, Queue => $self->Queue );
-    unless ( $cf->id ) {
-        $cf->LoadByNameAndQueue( Name => $field, Queue => 0 );
-    }
-
-    # If we didn't find a valid cfid, give up.
-    return RT::ObjectCustomFieldValues->new( $self->CurrentUser ) unless $cf->id;
-
-    return $self->SUPER::CustomFieldValues( $cf->id );
+    $cf->LoadByNameAndQueue( Name => $field, Queue => 0 ) unless $cf->id;
+    return $cf;
 }
 
 
-
 =head2 CustomFieldLookupType
 
 Returns the RT::Ticket lookup type, which can be passed to