starting to work...
[freeside.git] / rt / lib / RT / ObjectCustomField.pm
index 14bb61b..0b815ae 100644 (file)
@@ -2,7 +2,7 @@
 #
 # COPYRIGHT:
 #
-# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
 #                                          <sales@bestpractical.com>
 #
 # (Except where explicitly superseded by other copyright notices)
 #
 # END BPS TAGGED 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 !!
-#
+package RT::ObjectCustomField;
 
 use strict;
+use warnings;
 
 
-=head1 NAME
+use RT::CustomField;
+use base 'RT::Record';
 
-RT::ObjectCustomField
+sub Table {'ObjectCustomFields'}
 
 
-=head1 SYNOPSIS
 
-=head1 DESCRIPTION
 
-=head1 METHODS
 
-=cut
 
-package RT::ObjectCustomField;
-use RT::Record; 
-use RT::CustomField;
+sub Create {
+    my $self = shift;
+    my %args = (
+        CustomField => 0,
+        ObjectId    => 0,
+        SortOrder   => undef,
+        @_
+    );
+
+    my $cf = $self->CustomFieldObj( $args{'CustomField'} );
+    unless ( $cf->id ) {
+        $RT::Logger->error("Couldn't load '$args{'CustomField'}' custom field");
+        return 0;
+    }
+
+    #XXX: Where is ACL check for 'AssignCustomFields'?
+
+    my $ObjectCFs = RT::ObjectCustomFields->new($self->CurrentUser);
+    $ObjectCFs->LimitToObjectId( $args{'ObjectId'} );
+    $ObjectCFs->LimitToCustomField( $cf->id );
+    $ObjectCFs->LimitToLookupType( $cf->LookupType );
+    if ( my $first = $ObjectCFs->First ) {
+        $self->Load( $first->id );
+        return $first->id;
+    }
+
+    unless ( defined $args{'SortOrder'} ) {
+        my $ObjectCFs = RT::ObjectCustomFields->new( RT->SystemUser );
+        $ObjectCFs->LimitToObjectId( $args{'ObjectId'} );
+        $ObjectCFs->LimitToObjectId( 0 ) if $args{'ObjectId'};
+        $ObjectCFs->LimitToLookupType( $cf->LookupType );
+        $ObjectCFs->OrderBy( FIELD => 'SortOrder', ORDER => 'DESC' );
+        if ( my $first = $ObjectCFs->First ) {
+            $args{'SortOrder'} = $first->SortOrder + 1;
+        } else {
+            $args{'SortOrder'} = 0;
+        }
+    }
+
+    return $self->SUPER::Create(
+        CustomField => $args{'CustomField'},
+        ObjectId    => $args{'ObjectId'},
+        SortOrder   => $args{'SortOrder'},
+    );
+}
 
+sub Delete {
+    my $self = shift;
 
-use vars qw( @ISA );
-@ISA= qw( RT::Record );
+    my $ObjectCFs = RT::ObjectCustomFields->new($self->CurrentUser);
+    $ObjectCFs->LimitToObjectId($self->ObjectId);
+    $ObjectCFs->LimitToLookupType($self->CustomFieldObj->LookupType);
 
-sub _Init {
-  my $self = shift; 
+    # Move everything below us up
+    my $sort_order = $self->SortOrder;
+    while (my $OCF = $ObjectCFs->Next) {
+        my $this_order = $OCF->SortOrder;
+        next if $this_order <= $sort_order; 
+        $OCF->SetSortOrder($this_order - 1);
+    }
 
-  $self->Table('ObjectCustomFields');
-  $self->SUPER::_Init(@_);
+    $self->SUPER::Delete;
 }
 
 
+=head2 CustomFieldObj
 
+Returns the CustomField Object which has the id returned by CustomField
 
 
-=head2 Create PARAMHASH
+=cut
 
-Create takes a hash of values and creates a row in the database:
+sub CustomFieldObj {
+    my $self = shift;
+    my $id = shift || $self->CustomField;
+    my $CF = RT::CustomField->new( $self->CurrentUser );
+    $CF->Load( $id );
+    return $CF;
+}
 
-  int(11) 'CustomField'.
-  int(11) 'ObjectId'.
-  int(11) 'SortOrder'.
+=head2 Sorting custom fields applications
 
-=cut
+Custom fields sorted on multiple layers. First of all custom
+fields with different lookup type are sorted independently. All
+global custom fields have fixed order for all objects, but you
+can insert object specific custom fields between them. Object
+specific custom fields can be applied to several objects and
+be on different place. For example you have GCF1, GCF2, LCF1,
+LCF2 and LCF3 that applies to tickets. You can place GCF2
+above GCF1, but they will be in the same order in all queues.
+However, LCF1 and other local can be placed at any place
+for particular queue: above global, between them or below.
 
+=head3 MoveUp
 
+Moves custom field up. See </Sorting custom fields applications>.
 
+=cut
 
-sub Create {
+sub MoveUp {
     my $self = shift;
-    my %args = ( 
-                CustomField => '0',
-                ObjectId => '0',
-                SortOrder => '0',
-
-                 @_);
-    $self->SUPER::Create(
-                         CustomField => $args{'CustomField'},
-                         ObjectId => $args{'ObjectId'},
-                         SortOrder => $args{'SortOrder'},
-);
 
+    my $ocfs = RT::ObjectCustomFields->new( $self->CurrentUser );
+
+    my $oid = $self->ObjectId;
+    $ocfs->LimitToObjectId( $oid );
+    if ( $oid ) {
+        $ocfs->LimitToObjectId( 0 );
+    }
+
+    my $cf = $self->CustomFieldObj;
+    $ocfs->LimitToLookupType( $cf->LookupType );
+
+    $ocfs->Limit( FIELD => 'SortOrder', OPERATOR => '<', VALUE => $self->SortOrder );
+    $ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'DESC' } );
+
+    my @above = ($ocfs->Next, $ocfs->Next);
+    unless ($above[0]) {
+        return (0, "Can not move up. It's already at the top");
+    }
+
+    my $new_sort_order;
+    if ( $above[0]->ObjectId == $self->ObjectId ) {
+        $new_sort_order = $above[0]->SortOrder;
+        my ($status, $msg) = $above[0]->SetSortOrder( $self->SortOrder );
+        unless ( $status ) {
+            return (0, "Couldn't move custom field");
+        }
+    }
+    elsif ( $above[1] && $above[0]->SortOrder == $above[1]->SortOrder + 1 ) {
+        my $move_ocfs = RT::ObjectCustomFields->new( RT->SystemUser );
+        $move_ocfs->LimitToLookupType( $cf->LookupType );
+        $move_ocfs->Limit(
+            FIELD => 'SortOrder',
+            OPERATOR => '>=',
+            VALUE => $above[0]->SortOrder,
+        );
+        $move_ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'DESC' } );
+        while ( my $record = $move_ocfs->Next ) {
+            my ($status, $msg) = $record->SetSortOrder( $record->SortOrder + 1 );
+            unless ( $status ) {
+                return (0, "Couldn't move custom field");
+            }
+        }
+        $new_sort_order = $above[0]->SortOrder;
+    } else {
+        $new_sort_order = $above[0]->SortOrder - 1;
+    }
+
+    my ($status, $msg) = $self->SetSortOrder( $new_sort_order );
+    unless ( $status ) {
+        return (0, "Couldn't move custom field");
+    }
+
+    return (1,"Moved custom field up");
 }
 
+=head3 MoveDown
+
+Moves custom field down. See </Sorting custom fields applications>.
+
+=cut
+
+sub MoveDown {
+    my $self = shift;
+
+    my $ocfs = RT::ObjectCustomFields->new( $self->CurrentUser );
+
+    my $oid = $self->ObjectId;
+    $ocfs->LimitToObjectId( $oid );
+    if ( $oid ) {
+        $ocfs->LimitToObjectId( 0 );
+    }
+
+    my $cf = $self->CustomFieldObj;
+    $ocfs->LimitToLookupType( $cf->LookupType );
+
+    $ocfs->Limit( FIELD => 'SortOrder', OPERATOR => '>', VALUE => $self->SortOrder );
+    $ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'ASC' } );
+
+    my @below = ($ocfs->Next, $ocfs->Next);
+    unless ($below[0]) {
+        return (0, "Can not move down. It's already at the bottom");
+    }
+
+    my $new_sort_order;
+    if ( $below[0]->ObjectId == $self->ObjectId ) {
+        $new_sort_order = $below[0]->SortOrder;
+        my ($status, $msg) = $below[0]->SetSortOrder( $self->SortOrder );
+        unless ( $status ) {
+            return (0, "Couldn't move custom field");
+        }
+    }
+    elsif ( $below[1] && $below[0]->SortOrder + 1 == $below[1]->SortOrder ) {
+        my $move_ocfs = RT::ObjectCustomFields->new( RT->SystemUser );
+        $move_ocfs->LimitToLookupType( $cf->LookupType );
+        $move_ocfs->Limit(
+            FIELD => 'SortOrder',
+            OPERATOR => '<=',
+            VALUE => $below[0]->SortOrder,
+        );
+        $move_ocfs->OrderByCols( { FIELD => 'SortOrder', ORDER => 'ASC' } );
+        while ( my $record = $move_ocfs->Next ) {
+            my ($status, $msg) = $record->SetSortOrder( $record->SortOrder - 1 );
+            unless ( $status ) {
+                return (0, "Couldn't move custom field");
+            }
+        }
+        $new_sort_order = $below[0]->SortOrder;
+    } else {
+        $new_sort_order = $below[0]->SortOrder + 1;
+    }
+
+    my ($status, $msg) = $self->SetSortOrder( $new_sort_order );
+    unless ( $status ) {
+        return (0, "Couldn't move custom field");
+    }
+
+    return (1,"Moved custom field down");
+}
 
 
 =head2 id
 
-Returns the current value of id. 
+Returns the current value of id.
 (In the database, id is stored as int(11).)
 
 
@@ -129,7 +295,7 @@ Returns the current value of id.
 
 =head2 CustomField
 
-Returns the current value of CustomField. 
+Returns the current value of CustomField.
 (In the database, CustomField is stored as int(11).)
 
 
@@ -137,7 +303,7 @@ Returns the current value of CustomField.
 =head2 SetCustomField VALUE
 
 
-Set CustomField to VALUE. 
+Set CustomField to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, CustomField will be stored as a int(11).)
 
@@ -145,23 +311,9 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=head2 CustomFieldObj
-
-Returns the CustomField Object which has the id returned by CustomField
-
-
-=cut
-
-sub CustomFieldObj {
-       my $self = shift;
-       my $CustomField =  RT::CustomField->new($self->CurrentUser);
-       $CustomField->Load($self->__Value('CustomField'));
-       return($CustomField);
-}
-
 =head2 ObjectId
 
-Returns the current value of ObjectId. 
+Returns the current value of ObjectId.
 (In the database, ObjectId is stored as int(11).)
 
 
@@ -169,7 +321,7 @@ Returns the current value of ObjectId.
 =head2 SetObjectId VALUE
 
 
-Set ObjectId to VALUE. 
+Set ObjectId to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, ObjectId will be stored as a int(11).)
 
@@ -179,7 +331,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 =head2 SortOrder
 
-Returns the current value of SortOrder. 
+Returns the current value of SortOrder.
 (In the database, SortOrder is stored as int(11).)
 
 
@@ -187,7 +339,7 @@ Returns the current value of SortOrder.
 =head2 SetSortOrder VALUE
 
 
-Set SortOrder to VALUE. 
+Set SortOrder to VALUE.
 Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 (In the database, SortOrder will be stored as a int(11).)
 
@@ -197,7 +349,7 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 
 =head2 Creator
 
-Returns the current value of Creator. 
+Returns the current value of Creator.
 (In the database, Creator is stored as int(11).)
 
 
@@ -206,7 +358,7 @@ Returns the current value of Creator.
 
 =head2 Created
 
-Returns the current value of Created. 
+Returns the current value of Created.
 (In the database, Created is stored as datetime.)
 
 
@@ -215,7 +367,7 @@ Returns the current value of Created.
 
 =head2 LastUpdatedBy
 
-Returns the current value of LastUpdatedBy. 
+Returns the current value of LastUpdatedBy.
 (In the database, LastUpdatedBy is stored as int(11).)
 
 
@@ -224,7 +376,7 @@ Returns the current value of LastUpdatedBy.
 
 =head2 LastUpdated
 
-Returns the current value of LastUpdated. 
+Returns the current value of LastUpdated.
 (In the database, LastUpdated is stored as datetime.)
 
 
@@ -234,22 +386,22 @@ Returns the current value of LastUpdated.
 
 sub _CoreAccessible {
     {
-     
+
         id =>
                {read => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
-        CustomField => 
+        CustomField =>
+               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+        ObjectId =>
+               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => ''},
+        SortOrder =>
                {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
-        ObjectId => 
-               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
-        SortOrder => 
-               {read => 1, write => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
-        Creator => 
+        Creator =>
                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
-        Created => 
+        Created =>
                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
-        LastUpdatedBy => 
+        LastUpdatedBy =>
                {read => 1, auto => 1, sql_type => 4, length => 11,  is_blob => 0,  is_numeric => 1,  type => 'int(11)', default => '0'},
-        LastUpdated => 
+        LastUpdated =>
                {read => 1, auto => 1, sql_type => 11, length => 0,  is_blob => 0,  is_numeric => 0,  type => 'datetime', default => ''},
 
  }
@@ -257,23 +409,4 @@ sub _CoreAccessible {
 
 RT::Base->_ImportOverlays();
 
-=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.
-
-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::ObjectCustomField_Overlay, RT::ObjectCustomField_Vendor, RT::ObjectCustomField_Local
-
-=cut
-
-
 1;