Customer Company Notes Module

English! place to talk about development, programming and coding
Post Reply
dantheman972
Znuny newbie
Posts: 16
Joined: 11 Oct 2012, 00:11
Znuny Version: 3.100
Real Name: Dan S

Customer Company Notes Module

Post by dantheman972 »

Hi all, I've created a module that let's you add notes to the Customer Company screen allowing you to keep notes on each of the customers' companies you support. For instance, the company I work for has about 300 offices/branches that we support, we keep these organized as Customer Companies. This module allows us to keep notes on each office and easily access those notes by pulling up the customer company information center for that office. That being said Customer Company support MUST BE TURNED ON IN SYSCONFIG for this module to be of any use to you at all.

It features the ability to sticky notes to the top, and invalidate the notes if the user is an admin (but other groups can be added in the config, which we'll see later.)

Lastly before we get started please note that I am not a professional developer, this is my first time ever contributing to an open source project and this code should be heavily reviewed before being used in a production environment. You'll also see mentions of SBI which is the company I work, feel free to disregard.

First we need to create a table in our database like so:

Code: Select all

# 	Name 	Type 	Collation 	Attributes 	Null 	Default 	Extra
1      id 	         bigint(20) No 	None 	AUTO_INCREMENT
2 	company_id 	varchar(150) 	utf8_general_ci 		No 	None 	
3 	subject 	text 	utf8_general_ci 		Yes 	NULL 
4 	body 	mediumtext 	utf8_general_ci 		Yes 	NULL
5 	content_path 	varchar(250) 	utf8_general_ci 		Yes 	NULL 	
6 	content_type 	varchar(250) 	utf8_general_ci 		Yes 	NULL
7 	valid_id 	smallint(6) 			No 	None
8 	create_time 	datetime 			No 	None
9 	create_by 	int(11) 			No 	None
10 	change_time 	datetime 			No 	None
11 	change_by 	int(11) 			No 	None
12 	sticky 	tinyint(1) 			No 	None 	
Please note I basically copied this table structure from OTRS' "article" table. At present, content_path and content_type are not utilized and you can remove them but you would need to update the model file, CompanyNotes.pm accordingly. I've simply included them so later on I can add support for rich content type articles like those used for Ticket Notes, for now it's simply plain text.

Next is the config file, otrs/Kernel/Config/Files/SBICustom.xml

Code: Select all

<?xml version="1.0" encoding="UTF-8" ?>
<otrs_config version="1.0" init="Application">
        <ConfigItem Name="AgentCustomerInformationCenter::Backend###CompanyNotes" Required="1" Valid="1">
        <Description Lang="en">Registration for custom SBI Module to create and display notes for CustomerCompany's, referred to as Site Codes within SBI.</Description>
        <Group>SBICustom</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <Hash>
                <Item Key="Module">Kernel::Output::HTML::DashboardCompanyNotes</Item>
                <Item Key="Title" Translatable="1">Customer Company Notes</Item>
                <Item Key="Description" Translatable="1">Customer Company Notes</Item>
                <Item Key="Attributes"></Item>
                <Item Key="Block">ContentSmall</Item>
                <Item Key="Group"></Item>
                <Item Key="Default">1</Item>
            </Hash>
        </Setting>
    </ConfigItem>
    <ConfigItem Name="Kernel::Output::HTML::DashboardCompanyNotes::PermissionGroup" Required="1" Valid="1">
        <Description Translatable="1">Specifies the group that can delete and sticky notes in CompanyNotes module.</Description>
        <Group>SBICustom</Group>
        <SubGroup>Frontend::Agent::Dashboard</SubGroup>
        <Setting>
            <String Regex="">admin</String>
        </Setting>
    </ConfigItem>
</otrs_config>
Next we need to add the following bits to otrs/Kernel/System/CustomerCompany.pm, you will of course want to make a copy and place it in otrs/Custom/Kernel/System/CustomerCompany.pm

This needs to be added at the top, right after "use warnings;" will be fine. I've placed comments around my modifications.

Code: Select all

package Kernel::System::CustomerCompany;

use strict;
use warnings;

##SBI MOD - Include custom CompanyNotes module##
use Kernel::System::CustomerCompany::CompanyNotes;
##SBI MOD##
use Kernel::System::Valid;
use Kernel::System::Cache;
And then this will be added in the 'new' subroutine:

Code: Select all

sub new {
    my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {};
    bless( $Self, $Type );
	##SBI MOD - Include custom CompanyNotes module##
	@ISA = ('Kernel::System::CustomerCompany::CompanyNotes');
	##SBI MOD##

    # check needed objects
    for (qw(DBObject ConfigObject LogObject MainObject EncodeObject)) {
        $Self->{$_} = $Param{$_} || die "Got no $_!";
    }
Next we'll need to create a file, otrs/Custom/Kernel/System/CustomerCompany/CompanyNotes.pm

Code: Select all


#SBI MOD - 
#Kernel/System/CustomerCompany/CompanyNotes.pm - Module to load CompanyNotes for CustomerCompany object.

# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::System::CustomerCompany::CompanyNotes;
use strict;
use warnings;

use Kernel::System::User;
use Kernel::System::Group;
use Kernel::System::Cache;
use Kernel::System::Web::UploadCache;
use Kernel::System::HTMLUtils;


use vars qw($VERSION);
$VERSION = qw($Revision: 1.328 $) [1];

sub CompanyNoteGet {
	my ( $Self, %Param ) = @_;
	 
	if ( !$Param{CompanyArticleID}) {
        $Self->{LogObject}->Log( Priority => 'error', Message => 'Need CompanyArticleID!' );
        return;
    }
	
	
 # sql query
    my @Content;
    my @Bind;
    my $SQL = '
		SELECT id, company_id, subject, body, valid_id, create_time, create_by, change_time, change_by, sticky FROM company_article WHERE id = ?';
	push @Bind, \$Param{CompanyArticleID};
	return if !$Self->{DBObject}->Prepare( SQL => $SQL, Bind => \@Bind,);
	if (my @Row = $Self->{DBObject}->FetchrowArray()) {
	my	%Data = (

		NoteID => $Row[0],
		CustomerID => $Row[1],
		Subject => $Row[2],
		Body => $Row[3],
		Valid => $Row[4],
		CreateTime => $Row[5],
		CreateBy => $Row[6],
		ChangeTime => $Row[7],
		ChangeBy => $Row[8],
		Sticky => $Row[9],
		);
	return %Data;
	
	    # return if content is empty
    } else {

        # Log an error only if a specific article was requested and there is no filter active.
        if ( $Param{CompanyArticleID}) {
            $Self->{LogObject}->Log(
                Priority => 'error',
                Message  => "No such article for CompanyArticleID ($Param{CompanyArticleID})!",
            );
        }

        return;
	}
} ##End CompanyNoteGet function definition

sub CompanyNoteIndex {
	my ( $Self, %Param ) = @_;
	my @Index;
	my @Bind;
	my $Limit;

	if ( !$Param{CustomerID}) {
        $Self->{LogObject}->Log( Priority => 'error', Message => 'CompanyNoteIndex: Need CustomerID!' );
        return;
    }

    if ($Param{Limit}){ $Limit = $Param{Limit}; }
    else { $Limit = 1000;}
	$Bind[0]= \$Param{CustomerID};
	
	#We need to do two searches, once where we search for sticky notes (Sticky = 1)
	#and a second time for regular notes (Sticky = 0), this way the sticky notes
	#will always be at the top of our results. We'll do this with the following 
	#foreach loop.

	foreach my $i (1, 0){

		##Don't do another search if we already hit our limit.
		next if $Limit <= 0;
		##For our Bind variable, our site code should already be in position 0,
		##here we're putting our bind value for weather or not we want sticky notes.
		##The foreach loop will search 1 first for sticky notes, the 0 for other notes.
		$Bind[1] = \$i;
		#SQL Query
		my $SQL ='
			SELECT id FROM company_article WHERE company_id = ? AND sticky = ?';
		
		if (!$Param{ShowInvalid}) {
			$SQL .= ' AND valid_id = 1';
		}
		
		$SQL .= ' ORDER BY create_time DESC';
		
		return if !$Self->{DBObject}->Prepare( SQL => $SQL, Bind => \@Bind, Limit => $Limit);
		

	    while ( my @Row = $Self->{DBObject}->FetchrowArray() ) { push @Index, $Row[0]; 
	    	$Limit--;}
    }

return @Index;
} ##End CompanyNoteIndex function definition

sub CompanyNoteContentIndex {
	my ( $Self, %Param ) = @_;
	my @NoteContent;
	my @NoteIndex;
	
	if (!$Param{CustomerID} && !$Param{NoteIndex} && ref($Param{NoteIndex}) ne "ARRAY") {
        $Self->{LogObject}->Log( Priority => 'error', Message => 'CustomerNotes.pm: Need CustomerID or ContentIndex!' );
        return;
    }

    ##If we weren't provided a list of tickets, or what we were provided is not an array
    if (!$Param{NoteIndex} || ref($Param{NoteIndex}) ne "ARRAY"){
    	@NoteIndex = $Self->CompanyNoteIndex( CustomerID => $Param{CustomerID},)
    	} else {
    		@NoteIndex = @{$Param{NoteIndex}}
    	}

	##Once we have our ticket list, run a search on the tickts.
	if(@NoteIndex) {
		my $Count = 0;
		foreach my $NoteID (@NoteIndex){
			my %Content = $Self->CompanyNoteGet( CompanyArticleID => $NoteID, );
			push(@NoteContent, {%Content});
		}
	
	return @NoteContent; } else { return; }
	
} ##End CompanyNoteConIndex function definition

sub CompanyNoteCreate {
	my ( $Self, %Param ) = @_;

	for (qw(CustomerID UserID NoteSubject NoteBody))	{
		my $key = $_;
		if ( !$Param{$key}) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "CreateCompanyNote: Need $key !");
        return;
    }	}

    return if !$Self->{DBObject}->Do(
    		SQL => 'INSERT INTO company_article '
    		. '(company_id, subject, body, valid_id, create_time, create_by, change_time, change_by, '
    		. 'sticky)'
    		. ' VALUES (?, ?, ?, 1, current_timestamp, ?, current_timestamp, ?, 0)'	,
    		Bind => [
    		\$Param{CustomerID}, \$Param{NoteSubject}, \$Param{NoteBody},
    		\$Param{UserID}, \$Param{UserID},
    		],
    	);

    return 1;
} ##End CompanyNoteCreate definition.

sub CompanyNoteInvalidate {
	my ( $Self, %Param ) = @_;

	##Check to make sure we have all needed items.
	for (qw(CompanyArticleID CustomerID UserID))	{
		my $key = $_;
		if ( !$Param{$key}) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "CompanyNoteInvalidate: Need $key !");
        return 0;
    }	}

    ##Get the note's content so we can check it and log it.
    my %Note =$Self->CompanyNoteGet(
    	CompanyArticleID => $Param{CompanyArticleID}
    	);

    ##Check to make sure that the note exists, that it is still valid and that the CustomerID
    ##provided matches the one on the note.
    if(!%Note || !$Note{Valid} || $Note{CustomerID} ne $Param{CustomerID}){ return; }
    ##Do the SQL query
    return if !$Self->{DBObject}->Do(
    	SQL => 'UPDATE company_article SET valid_id = 0, change_time = current_timestamp, change_by = ? WHERE id = ? AND company_id = ?',
    	Bind =>[
    	\$Param{UserID}, \$Param{CompanyArticleID}, \$Param{CustomerID},
    	],
    );	

    ##Log the note being invalidated, mostly for auditing purposes.
    $Self->{LogObject}->Log(
        Priority => 'notice',
        Message  => "Note was invalidated by UserID: $Param{UserID} CustomerID: $Param{CustomerID} NoteSubject: $Note{Subject} NoteBody: $Note{Body}",
    );

    return 1;
} ##End CompanyNoteInvalidate definition.

sub CompanyNoteSticky {
	my ( $Self, %Param ) = @_;
	my $Sticky = 0;

	##Check to make sure we have all needed items.
	for (qw(CustomerID CompanyArticleID UserID))	{
		my $key = $_;
		if ( !$Param{$key}) {
        $Self->{LogObject}->Log( Priority => 'error', Message => "CompanyNoteSticky: Need $key !");
        return;
    }	}

       my %Note =$Self->CompanyNoteGet(
    	CompanyArticleID => $Param{CompanyArticleID}
    	);

    ##Check to make sure that the note exists and that the CustomerID
    ##provided matches the one on the note.
    if(!%Note || $Note{CustomerID} ne $Param{CustomerID}){ return; }
    
    ##Check to see if the note is stickied or not already.
    if(!$Note{Sticky}){ $Sticky = 1;}

    return if !$Self->{DBObject}->Do(
    	SQL => 'UPDATE company_article SET sticky = ?, change_time = current_timestamp, change_by = ? WHERE id = ? AND company_id = ?',
    	Bind =>[
    	\$Sticky, \$Param{UserID}, \$Param{CompanyArticleID}, \$Param{CustomerID},
    	],
    );	
    return 1;
}

1;
Next otrs/Custom/Kernel/Output/HTML/DashboardCompanyNotes.pm:

Code: Select all

##SBI MOD - Custom module to allow creation and retrieval of CustomerCompanyNotes on the CustomerCompany Information Center. 
##This is the Controller, it is loaded by the sysonfig backend.

# This software comes with ABSOLUTELY NO WARRANTY. For details, see
# the enclosed file COPYING for license information (AGPL). If you
# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
# --

package Kernel::Output::HTML::DashboardCompanyNotes;


use Kernel::System::Web::UploadCache;
use strict;
use warnings;

sub new {
	my ( $Type, %Param ) = @_;

    # allocate new hash for object
    my $Self = {%Param};
    bless( $Self, $Type );
	
	# 
	for my $Needed (
        qw(ParamObject DBObject CustomerCompanyObject LayoutObject LogObject QueueObject UserObject ConfigObject GroupObject)
        )
    {
        if ( !$Self->{$Needed} ) {
            $Self->{LayoutObject}->FatalError( Message => "Got no $Needed!" );
        }
    }


	$Self->{PrefKey} = 'UserDashboardPref' . $Self->{Name} . '-Shown';

    $Self->{PageShown} = $Self->{LayoutObject}->{ $Self->{PrefKey} } || $Self->{Config}->{Limit};

    $Self->{StartHit} = int( $Self->{ParamObject}->GetParam( Param => 'StartHit' ) || 1 );
	
	$Self->{NoteAction} = $Self->{ParamObject}->GetParam( Param => 'NoteAction' );
	return $Self;
}

sub Preferences {
    my ( $Self, %Param ) = @_;

    my @Params = (
        {
            Desc  => 'Shown Tickets',
            Name  => $Self->{PrefKey},
            Block => 'Option',

            #            Block => 'Input',
            Data => {
                5  => ' 5',
                10 => '10',
            },
            SelectedID  => $Self->{PageShown},
            Translation => 0,
        },
    );

    return @Params;
}

sub Config {
    my ( $Self, %Param ) = @_;

    return (
        %{ $Self->{Config} },

        # caching not needed
        CacheKey => undef,
        CacheTTL => undef,
    );
}

sub Run {
	my ( $Self, %Param ) = @_;

	return if !$Param{CustomerID};

	##Check the config for group permissions to edit, invalidate and sticky notes. This is by default, the 'admin' group. This setting can be accessed
	##in the SBICustom sysconfig category.
	my $NotesAdminGroupID = $Self->{GroupObject}->GroupLookup(
		Group => $Self->{ConfigObject}->Get('Kernel::Output::HTML::DashboardCompanyNotes::PermissionGroup'),
	);

    # get user groups, where the user has the rw privilege
    my %Groups = $Self->{GroupObject}->GroupMemberList(
        UserID => $Self->{UserID},
        Type   => 'rw',
        Result => 'HASH',
    );

    # if the user is a member in this group they can access the feature
    if ( $Groups{$NotesAdminGroupID} ) {
        $Self->{NotesAdmin} = 1;
    }

    ##Note creation
	if ($Self->{NoteAction} && $Self->{NoteAction} eq 'CompanyNoteCreate'){
	    my %GetParam;
	    for my $Key (qw(NoteSubject NoteBody))
	    {
	        $GetParam{$Key} = $Self->{ParamObject}->GetParam( Param => $Key );
	    }
	    ##Need to add error checking. CompanyNoteCreate should return 1 or 0 based on success.
		my $AddNote = $Self->{CustomerCompanyObject}->CompanyNoteCreate (
		 		CustomerID => $Param{CustomerID},
		 		UserID => $Self->{UserID},
		 		NoteSubject => $GetParam{NoteSubject},
		 		NoteBody => $GetParam{NoteBody},
		 		);
	} ## End CompanyNoteCreate if branch.

	##Note invalidation
	if ($Self->{NoteAction} && $Self->{NoteAction} eq 'CompanyNoteInvalidate') {
		##Check permissions..
		if($Self->{NotesAdmin}){
			my %GetParam;
	    	for my $Key (qw(CompanyArticleID CustomerID)) {
	    		$GetParam{$Key} = $Self->{ParamObject}->GetParam( Param => $Key );
	    	}
	    ##Try to invalidate the note...
	    my $InvalidateNote = $Self->{CustomerCompanyObject}->CompanyNoteInvalidate(
	    		CompanyArticleID => $GetParam{CompanyArticleID},
	    		CustomerID => $GetParam{CustomerID},
	    		UserID => $Self->{UserID},
	    	);
	    ##If note invalidate was successfull...
	    if($InvalidateNote){
	    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Message => 'Note successfully invalidated!'},
	    	);
	    ##Otherwise..
	    } else {
	    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Error => 'There was a problem invalidating the note! (It is probably already invalidated, doesn\'t exist or you don\'t have permission.)'},
	    	);
	    }
	    ##If we don't have permission..
	    } else { 
			    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Error => 'You don\'t have permission to do that!'},
	    	);
	}} ## End CompanyNoteInvalidate if branch.


	##Sticky a note
	if ($Self->{NoteAction} && $Self->{NoteAction} eq 'CompanyNoteSticky'){
		##Check permissions..
		if($Self->{NotesAdmin}){

			my %GetParam;
		    	for my $Key (qw(CompanyArticleID CustomerID)) {
		    		$GetParam{$Key} = $Self->{ParamObject}->GetParam( Param => $Key );
	    	}

	    ##Try to stick the note...	
	    my $StickyNote = $Self->{CustomerCompanyObject}->CompanyNoteSticky(
	    		
	    		CustomerID => $GetParam{CustomerID},
	    		CompanyArticleID => $GetParam{CompanyArticleID},
	    		UserID=> $Self->{UserID},
	    	);
	    ##If note sticky was successfull...
	    if($StickyNote){
	    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Message => 'Note successfully stickied!'},
	    	);
	    ##Otherwise...
	    } else {
	    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Error => 'There was a problem stickying the note! ',});
	    }
	    ##If we don't have permission..
		} else { 
			    	$Self->{LayoutObject}->Block(
	    		Name => 'Notification',
	    		Data => {Error => 'You don\'t have permission to do that!'},
	    	);
	}} ## End CompanyNoteSticky if branch.


	##Get our index of notes...
	my @NoteIndex = $Self->{CustomerCompanyObject}->CompanyNoteIndex(
			CustomerID => $Param{CustomerID}
		);

	##If we have notes, start working through them below.
	if(@NoteIndex){

				##Get a count of the number of notes we got back.
		my $Total = scalar @NoteIndex;

		##Help build the URL for our AJAX request
	    my $LinkPage
	        = 'Subaction=Element;Name='
	        . $Self->{Name} . ';'
	        . 'CustomerID='
	        . $Self->{LayoutObject}->LinkEncode( $Param{CustomerID} ) . ';';
	    ##List Layout Object method creates the pagination, I'll be damned if I know it works
		my %PageNav = $Self->{LayoutObject}->PageNavBar(
	        StartHit    => $Self->{StartHit},           # start to show items
	        PageShown   => $Self->{PageShown},          # number of shown items a page
	        AllHits     => $Total || 1,          # number of total hits
			Action => 'Action=' . $Self->{LayoutObject}->{Action},  # e. g. 'Action=' . $Self->{LayoutObject}->{Action}
	        Link        =>  $LinkPage,       # e. g. 'Subaction=View;'
	        AJAXReplace => 'Dashboard'.$Self->{Name}, # IDElement which should be replaced
	        IDPrefix    => 'Dashboard'.$Self->{Name},   # Prefix for the id parameter
	        KeepScriptTags => $Param{AJAX},
			);

	    $Self->{LayoutObject}->Block(
	        Name => 'CompanyNotesNavBar',
	        Data => {
	            %{ $Self->{Config} },
	            Name => $Self->{Name},
	            %PageNav,
	        },
	    );

	    ##Splice through our NoteIndex array and grab only the notes for the page we're loading.
		@NoteIndex = splice @NoteIndex, $Self->{StartHit} -1, $Self->{PageShown};

		$Self->{LayoutObject}->Block(
			Name=>"DashboardCompanyNotesBox"
		);

		##Start working through the notes
		for my $Note (@NoteIndex){

			##Use CompanyNoteGet to retrieve the contents of each note
			my %NoteContent = $Self->{CustomerCompanyObject}->CompanyNoteGet(
					CompanyArticleID => $Note,
				);

		##Get the user's real name in a human readable format, if possible.
		my $UserName;	
			if ( my %User = $Self->{UserObject}->GetUserData( UserID => $NoteContent{CreateBy},) ){
				$UserName = $User{UserFirstname}." ".$User{UserLastname};
				} else {
				$UserName = $NoteContent{ChangeBy};
				}

			##Send Note content to output
			$Self->{LayoutObject}->Block(
				Name => 'DashboardCompanyNotesBoxRow',
				Data => {
					Subject => $NoteContent{Subject},
					Body => $NoteContent{Body},
					User => $UserName,
					Date => $NoteContent{CreateTime},
				},);

			##If the note is a sticky, set it's CSS class.
			if($NoteContent{Sticky}){
				$Self->{LayoutObject}->Block(
					Name => 'DashboardCompanyNotesBoxRowSticky',
					Data =>{
						StickyClass => "StickyNote",
					},
					);
			}
			##If user has admin rights, send admin options.
			if($Self->{NotesAdmin}){
				$Self->{LayoutObject}->Block(
					Name => 'DashboardCompanyNotesBoxRowAdmin',
					Data => {NoteID => $NoteContent{NoteID},
							 CustomerID => $Param{CustomerID}
							 }
				);
			}

		}
	
	##If we don't have any notes, display a default message.
	}	else {

	$Self->{LayoutObject}->Block(
				Name => 'Notification',
				Data => { Message => "No notes yet for this office! Please add one below:",},
			);}
	
	##This bit feeds our CustomerID to our HTML form, that is all.
	$Self->{LayoutObject}->Block(
    		Name => 'DashboardCompanyNotesForm',
    		Data => {CustomerID => $Param{CustomerID},},
    	);
	

	##Flip the content onto the screen.
	my $Content = $Self->{LayoutObject}->Output(
		TemplateFile => 'CompanyNotes',
		Data => {
            %{ $Self->{Config} },
            Name => $Self->{Name},
		},
		KeepScriptTags => $Param{AJAX},
	);

	return $Content;
}

sub _AJAXUpdate {


}

1;
Lastly we create otrs/Custom/Kernel/Output/HTML/Standard/CompanyNotes.dtl

Code: Select all

<script type="text/javascript">

function confirmDel()
	{
		return confirm('Are you sure you want to invalidate(hide) this note?');
	}

function showAdd()
	{
		$('#AddNote').toggle();
		$('#AddButton').toggle();
	}	

</script>
<style type="text/css">
	.StickyNote.CompanyNotesTR {
		Background: #FCF0AD;
	}
	.CompanyNotesTR {
		Background: #FFFFFF;
		border-bottom: 1px solid black;
	}
	.StickyNote.Even.CompanyNotesTR{
		Background: #FAFAD2;
	}
	.Even.CompanyNotesTR {
		Background: #EDEDED;
	}
	.CompanyNotesTD {
		padding: 10px 4px 10px 4px;
	}
	.CompanyNotesTR.Last {
		border: 0;
	}
	.CompanyNotesFoot {
		font-size: 10px;
	}
	.CompanyNotesSubject {
		padding-bottom: 4px;
		border-bottom: 1px dashed black;
		font-weight: bold;
	}
</style>
<div class="Clear"></div>
<!-- dtl:block:Notification -->
<span class="CompanyNotesError">$QData{"Error"}</span>
<span class="CompanyNoteNotice">$QData{"Message"}</span>
<!-- dtl:block:Notification -->
<div class="Clear"></div>
<!-- dtl:block:CompanyNotesNavBar -->
<span class="Pagination">
    $Data{"SiteNavBar"}
</span>
<!-- dtl:block:CompanyNotesNavBar -->
<div class="Clear"></div>
<!-- dtl:block:DashboardCompanyNotesBox -->
<table id="CompanyNotesTable">
    <tbody>

	<!-- dtl:block:DashboardCompanyNotesBoxRow -->
	<tr class="CompanyNotesTR
	<!-- dtl:block:DashboardCompanyNotesBoxRowSticky -->
	StickyNote
	<!-- dtl:block:DashboardCompanyNotesBoxRowSticky -->
	"><td class="CompanyNotesTD">
		<H2 Class = "CompanyNotesSubject">$QData{"Subject"}</H2>
		<P Class = "CompanyNotesBody">$QData{"Body"}</P><BR>
		<hr>
		<SPAN Class = "CompanyNotesFoot">Note added: $TimeShort{"$Data{"Date"}"} by $QData{"User"} 
	<!-- dtl:block:DashboardCompanyNotesBoxRowAdmin -->	

		| <a id="InvalidateNote$Data{"NoteID"}" href="#">Invalidate Note</a> -

<!-- dtl:js_on_document_complete -->
<script type="text/javascript">//<![CDATA[
    $('#InvalidateNote$Data{"NoteID"}').unbind('click').bind('click', function(){
    	if (confirmDel()){
	        var $Container = $(this).parents('.WidgetSimple');
	        $Container.addClass('Loading');
	        Core.AJAX.ContentUpdate($('#DashboardCompanyNotes'), '/otrs/index.pl?Action=AgentCustomerInformationCenter;Subaction=Element;Name=CompanyNotes;NoteAction=CompanyNoteInvalidate;CompanyArticleID=$Data{"NoteID"};CustomerID=$Data{"CustomerID"};', function () {
	            Core.UI.Table.InitCSSPseudoClasses($('#DashboardCompanyNotes'));
	            $Container.removeClass('Loading');
	        });
	        }
        return false;
    });
//]]></script>
<!-- dtl:js_on_document_complete -->

		<a id="StickyNote$Data{"NoteID"}" href="#">Sticky Note</a>
<!-- dtl:js_on_document_complete -->
<script type="text/javascript">//<![CDATA[
    $('#StickyNote$Data{"NoteID"}').unbind('click').bind('click', function(){
        var $Container = $(this).parents('.WidgetSimple');
        $Container.addClass('Loading');
        Core.AJAX.ContentUpdate($('#DashboardCompanyNotes'), '/otrs/index.pl?Action=AgentCustomerInformationCenter;Subaction=Element;Name=CompanyNotes;NoteAction=CompanyNoteSticky;CompanyArticleID=$Data{"NoteID"};CustomerID=$Data{"CustomerID"};', function () {
            Core.UI.Table.InitCSSPseudoClasses($('#DashboardCompanyNotes'));
            $Container.removeClass('Loading');
        });
        return false;
    });
//]]></script>
<!-- dtl:js_on_document_complete -->
	<!-- dtl:block:DashboardCompanyNotesBoxRowAdmin -->	
		</SPAN></td></tr>
	<!-- dtl:block:DashboardCompanyNotesBoxRow -->


	</tbody>
</table><BR/>
<!-- dtl:block:DashboardCompanyNotesBox -->
<BR>
<button onclick="showAdd()" id="AddButton">Add Note</button>
<BR>
<!-- dtl:block:DashboardCompanyNotesForm -->
<div id="AddNote" style="display:none;">
 <form action="$Env{"CGIHandle"}?Action=$Env{"Action"};CustomerID=$Data{"CustomerID"}" method="post" enctype="multipart/form-data" name="compose" id="NewCompanyNotes" class="Validate PreventMultipleSubmits">
<input type="hidden" name="Action" id="Action" value="$Env{"Action"}"/>

<input type="hidden" name="CustomerID" id="CustomerID" value="$Data{"CustomerID"}" />

<input type="hidden" name="NoteAction" id="NoteAction" value="CompanyNoteCreate" />
<input type="hidden" name="FormID" id="FormID" value="$QData{"FormID"}"/>
<input type="hidden" name="UserID" id="UserID" value='$QData{"UserID"}' />

<label for="NoteSubject">Note Subject: </label><BR>
<input type="text" name="NoteSubject" id="NoteSubject" class="Validate_Required"></input><BR>
<label for="NoteBody">Note Body: </label><BR>
<textarea name="NoteBody" id="NoteBody" value="Body" class="Validate_Required"></textarea><BR>
<input id ="CompanyNotesSave" type="submit" Value="Save Note" ></input> <button onclick="showAdd()">Cancel</button>


</form>
</div>
<!-- dtl:block:DashboardCompanyNotesForm -->

If you're still with me and you use this code, please, please, please give me your feedback! I don't have a lot of people to talk coding shop with so any feedback will help make me a better coder as I am primarily self taught.
dantheman972
Znuny newbie
Posts: 16
Joined: 11 Oct 2012, 00:11
Znuny Version: 3.100
Real Name: Dan S

Re: Customer Company Notes Module

Post by dantheman972 »

Some screen shots to pique your interest:
Image
Image
Image
Post Reply