1954 lines
61 KiB
Perl
1954 lines
61 KiB
Perl
# --
|
|
# Copyright (C) 2001-2019 OTRS AG, https://otrs.com/
|
|
# --
|
|
# This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
# the enclosed file COPYING for license information (GPL). If you
|
|
# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
|
|
# --
|
|
|
|
package Kernel::System::ITSMChange::Notification;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Storable;
|
|
|
|
use Kernel::System::VariableCheck qw(:all);
|
|
|
|
use Kernel::Language;
|
|
use Kernel::Language qw(Translatable);
|
|
use Kernel::System::EventHandler;
|
|
|
|
use vars qw(@ISA);
|
|
|
|
our @ObjectDependencies = (
|
|
'Kernel::Config',
|
|
'Kernel::System::Cache',
|
|
'Kernel::System::CustomerUser',
|
|
'Kernel::System::DB',
|
|
'Kernel::System::DynamicField',
|
|
'Kernel::System::DynamicField::Backend',
|
|
'Kernel::System::Email',
|
|
'Kernel::System::HTMLUtils',
|
|
'Kernel::System::ITSMChange',
|
|
'Kernel::System::ITSMChange::ITSMWorkOrder',
|
|
'Kernel::System::Log',
|
|
'Kernel::System::User',
|
|
'Kernel::System::Valid',
|
|
);
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::System::ITSMChange::Notification - notification functions for change management
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
This module is managing notifications.
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=cut
|
|
|
|
=head2 new()
|
|
|
|
Create a notification object.
|
|
|
|
use Kernel::System::ObjectManager;
|
|
local $Kernel::OM = Kernel::System::ObjectManager->new();
|
|
my $NotificationObject = $Kernel::OM->Get('Kernel::System::ITSMChange::Notification');
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
# allocate new hash for object
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
# set the debug flag
|
|
$Self->{Debug} = $Param{Debug} || 0;
|
|
|
|
# get the cache type and TTL (in seconds)
|
|
$Self->{CacheType} = 'ITSMChangeManagement';
|
|
$Self->{CacheTTL} = $Kernel::OM->Get('Kernel::Config')->Get('ITSMChange::CacheTTL') * 60;
|
|
|
|
# do we use richtext
|
|
$Self->{RichText} = $Kernel::OM->Get('Kernel::Config')->Get('Frontend::RichText');
|
|
|
|
@ISA = (
|
|
'Kernel::System::EventHandler',
|
|
);
|
|
|
|
# init of event handler
|
|
$Self->EventHandlerInit(
|
|
Config => 'ITSMChangeManagementNotification::EventModule',
|
|
);
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 NotificationSend()
|
|
|
|
Send the notification to customers and/or agents.
|
|
|
|
my $Success = $NotificationObject->NotificationSend(
|
|
AgentIDs => [ 1, 2, 3, ]
|
|
CustomerIDs => [ 1, 2, 3, ],
|
|
Type => 'Change', # Change|WorkOrder
|
|
Event => 'ChangeUpdate',
|
|
Data => { %ChangeData }, # Change|WorkOrder|Link data
|
|
Message => {
|
|
Agent => {
|
|
'en' => {
|
|
Subject => 'Hello Agent',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Agent',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
Customer => {
|
|
'en' => {
|
|
Subject => 'Hello Customer',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Kunde',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
},
|
|
UserID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub NotificationSend {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Argument (qw(Type Event UserID Data Message)) {
|
|
if ( !$Param{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Argument!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check message
|
|
for my $Type (qw(Agent Customer)) {
|
|
|
|
# check message parameter, we always need agent and message
|
|
if ( !IsHashRefWithData( $Param{Message}->{$Type} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check each argument for each message language
|
|
for my $Language ( sort keys %{ $Param{Message}->{$Type} } ) {
|
|
|
|
for my $Argument (qw(Subject Body ContentType)) {
|
|
|
|
# error if message data is incomplete
|
|
if ( !$Param{Message}->{$Type}->{$Language}->{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message argument '$Argument' for language '$Language'!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# for convenience
|
|
my $Event = $Param{Event};
|
|
|
|
# need at least AgentIDs or CustomerIDs
|
|
if ( !$Param{AgentIDs} && !$Param{CustomerIDs} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need at least AgentIDs or CustomerIDs!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# AgentIDs and CustomerIDs have to be array references
|
|
for my $IDKey (qw(AgentIDs CustomerIDs)) {
|
|
if ( defined $Param{$IDKey} && ref $Param{$IDKey} ne 'ARRAY' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "$IDKey has to be an array reference!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# check whether the sending of notification has been turned off
|
|
return 1 if !$Kernel::OM->Get('Kernel::Config')->Get('ITSMChange::SendNotifications');
|
|
|
|
# we need to get the items for replacements
|
|
my $Change = {};
|
|
my $WorkOrder = {};
|
|
my $Link = {};
|
|
|
|
# start with workorder, as the change id might be taken from the workorder
|
|
if ( $Param{Data}->{WorkOrderID} ) {
|
|
|
|
if ( $Event eq 'WorkOrderDelete' ) {
|
|
|
|
# the workorder is already deleted,
|
|
# so we display the old data
|
|
$WorkOrder = $Param{Data}->{OldWorkOrderData};
|
|
}
|
|
else {
|
|
|
|
# get fresh data
|
|
$WorkOrder = $Kernel::OM->Get('Kernel::System::ITSMChange::ITSMWorkOrder')->WorkOrderGet(
|
|
WorkOrderID => $Param{Data}->{WorkOrderID},
|
|
UserID => $Param{UserID},
|
|
LogNo => 1,
|
|
);
|
|
}
|
|
|
|
# The event 'WorkOrderAdd' is a special case, as the workorder
|
|
# is not completely initialized yet. So also take
|
|
# the params for WorkOrderAdd() into account.
|
|
# WorkOrderGet() must still be called, as it provides translation
|
|
# for some IDs that were set in WorkOrderAdd().
|
|
if ( $Event eq 'WorkOrderAdd' ) {
|
|
for my $Attribute ( sort keys %{$WorkOrder} ) {
|
|
$WorkOrder->{$Attribute} ||= $Param{Data}->{$Attribute};
|
|
}
|
|
}
|
|
|
|
if ( $WorkOrder->{WorkOrderAgentID} ) {
|
|
|
|
# get user data for the workorder agent
|
|
$Param{Data}->{WorkOrderAgent} = {
|
|
$Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $WorkOrder->{WorkOrderAgentID},
|
|
)
|
|
};
|
|
}
|
|
|
|
# infer the change id from the workorder
|
|
if ( $WorkOrder->{ChangeID} ) {
|
|
$Param{Data}->{ChangeID} = $WorkOrder->{ChangeID};
|
|
}
|
|
}
|
|
|
|
if ( $Param{Data}->{ChangeID} ) {
|
|
|
|
$Change = $Kernel::OM->Get('Kernel::System::ITSMChange')->ChangeGet(
|
|
ChangeID => $Param{Data}->{ChangeID},
|
|
UserID => $Param{UserID},
|
|
LogNo => 1,
|
|
);
|
|
|
|
# The event 'ChangeAdd' is a special case, as the change
|
|
# is not completely initialized yet. So also take
|
|
# the params for ChangeAdd() into account.
|
|
# ChangeGet() must still be called, as it provides translation
|
|
# for some IDs that were set in ChangeAdd().
|
|
if ( $Event eq 'ChangeAdd' ) {
|
|
for my $Attribute ( sort keys %{$Change} ) {
|
|
$Change->{$Attribute} ||= $Param{Data}->{$Attribute};
|
|
}
|
|
}
|
|
|
|
if ( $Change->{ChangeBuilderID} ) {
|
|
$Param{Data}->{ChangeBuilder} = {
|
|
$Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $Change->{ChangeBuilderID},
|
|
)
|
|
};
|
|
}
|
|
|
|
if ( $Change->{ChangeManagerID} ) {
|
|
$Param{Data}->{ChangeManager} = {
|
|
$Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $Change->{ChangeManagerID},
|
|
)
|
|
};
|
|
}
|
|
}
|
|
|
|
# for link events there is some info about the link
|
|
if ( $Event =~ m{ \A (?: Change | WorkOrder ) Link (?: Add | Delete ) }xms ) {
|
|
$Link = {
|
|
SourceObject => $Param{Data}->{SourceObject},
|
|
TargetObject => $Param{Data}->{TargetObject},
|
|
State => $Param{Data}->{State},
|
|
Type => $Param{Data}->{Type},
|
|
Object => $Param{Data}->{Object},
|
|
};
|
|
}
|
|
|
|
# get the valid ids
|
|
my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
|
|
my %ValidIDLookup = map { $_ => 1 } @ValidIDs;
|
|
|
|
my %AgentsSent;
|
|
|
|
AGENTID:
|
|
for my $AgentID ( @{ $Param{AgentIDs} } ) {
|
|
|
|
# check if notification was already sent to this agent
|
|
next AGENTID if $AgentsSent{$AgentID};
|
|
|
|
# user info for preferred language and macro replacement
|
|
my %User = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $AgentID,
|
|
);
|
|
|
|
# do not send emails to invalid agents
|
|
if ( exists $User{ValidID} && !$ValidIDLookup{ $User{ValidID} } ) {
|
|
next AGENTID;
|
|
}
|
|
|
|
# get system default language
|
|
my $DefaultLanguage = $Kernel::OM->Get('Kernel::Config')->Get('DefaultLanguage') || 'en';
|
|
|
|
# get user preferred language
|
|
my $PreferredLanguage = $User{UserLanguage} || $DefaultLanguage;
|
|
|
|
# make sure a message in the user language exists
|
|
if ( !$Param{Message}->{Agent}->{$PreferredLanguage} ) {
|
|
|
|
# otherwise use default language
|
|
$PreferredLanguage = $DefaultLanguage;
|
|
|
|
# if no message exists in default language, then take the first available language
|
|
if ( !$Param{Message}->{Agent}->{$PreferredLanguage} ) {
|
|
my @Languages = sort keys %{ $Param{Message}->{Agent} };
|
|
$PreferredLanguage = $Languages[0];
|
|
}
|
|
}
|
|
|
|
my $Notification = $Param{Message}->{Agent}->{$PreferredLanguage};
|
|
return if !$Notification;
|
|
|
|
# do text/plain to text/html convert
|
|
if ( $Self->{RichText} && $Notification->{ContentType} =~ m{ text/plain }xmsi ) {
|
|
$Notification->{ContentType} = 'text/html';
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $Notification->{Body},
|
|
);
|
|
}
|
|
|
|
# do text/html to text/plain convert
|
|
elsif ( !$Self->{RichText} && $Notification->{ContentType} =~ m{ text/html }xmsi ) {
|
|
$Notification->{ContentType} = 'text/plain';
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToAscii(
|
|
String => $Notification->{Body},
|
|
);
|
|
}
|
|
|
|
# replace otrs macros
|
|
$Notification->{Body} = $Self->_NotificationReplaceMacros(
|
|
Type => $Param{Type},
|
|
Text => $Notification->{Body},
|
|
Recipient => {%User},
|
|
RichText => $Self->{RichText},
|
|
UserID => $Param{UserID},
|
|
Change => $Change,
|
|
WorkOrder => $WorkOrder,
|
|
Link => $Link,
|
|
Data => $Param{Data},
|
|
Language => $PreferredLanguage,
|
|
);
|
|
|
|
$Notification->{Subject} = $Self->_NotificationReplaceMacros(
|
|
Type => $Param{Type},
|
|
Text => $Notification->{Subject},
|
|
Recipient => {%User},
|
|
UserID => $Param{UserID},
|
|
Change => $Change,
|
|
WorkOrder => $WorkOrder,
|
|
Link => $Link,
|
|
Data => $Param{Data},
|
|
Language => $PreferredLanguage,
|
|
);
|
|
|
|
# add urls and verify to be full html document
|
|
if ( $Self->{RichText} ) {
|
|
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->LinkQuote(
|
|
String => $Notification->{Body},
|
|
);
|
|
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->DocumentComplete(
|
|
Charset => 'utf-8',
|
|
String => $Notification->{Body},
|
|
);
|
|
}
|
|
|
|
# send notification
|
|
$Kernel::OM->Get('Kernel::System::Email')->Send(
|
|
From => $Kernel::OM->Get('Kernel::Config')->Get('NotificationSenderName') . ' <'
|
|
. $Kernel::OM->Get('Kernel::Config')->Get('NotificationSenderEmail') . '>',
|
|
To => $User{UserEmail},
|
|
Subject => $Notification->{Subject},
|
|
MimeType => $Notification->{ContentType} || 'text/plain',
|
|
Charset => 'utf-8',
|
|
Body => $Notification->{Body},
|
|
Loop => 1,
|
|
);
|
|
|
|
# get the event type
|
|
my $Type;
|
|
if ( $Event =~ m{ \A (Change|ActionExecute) }xms ) {
|
|
$Type = 'Change';
|
|
}
|
|
elsif ( $Event =~ m{ \A WorkOrder }xms ) {
|
|
$Type = 'WorkOrder';
|
|
}
|
|
|
|
# trigger NotificationSent-Event
|
|
$Self->EventHandler(
|
|
Event => $Type . 'NotificationSentPost',
|
|
Data => {
|
|
WorkOrderID => $WorkOrder->{WorkOrderID},
|
|
ChangeID => $Change->{ChangeID},
|
|
EventType => $Event,
|
|
To => $User{UserEmail},
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
$AgentsSent{$AgentID} = 1;
|
|
}
|
|
|
|
my %CustomersSent;
|
|
|
|
CUSTOMERID:
|
|
for my $CustomerID ( @{ $Param{CustomerIDs} } ) {
|
|
|
|
# check if notification was already sent to customer
|
|
next CUSTOMERID if $CustomersSent{$CustomerID};
|
|
|
|
# User info for prefered language and macro replacement
|
|
my %CustomerUser = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet(
|
|
User => $CustomerID,
|
|
);
|
|
|
|
# do not send emails to invalid customers
|
|
if ( exists $CustomerUser{ValidID} && !$ValidIDLookup{ $CustomerUser{ValidID} } ) {
|
|
next CUSTOMERID;
|
|
}
|
|
|
|
# get system default language
|
|
my $DefaultLanguage = $Kernel::OM->Get('Kernel::Config')->Get('DefaultLanguage') || 'en';
|
|
|
|
# get user preferred language
|
|
my $PreferredLanguage = $CustomerUser{UserLanguage} || $DefaultLanguage;
|
|
|
|
# make sure a message in the user language exists
|
|
if ( !$Param{Message}->{Customer}->{$PreferredLanguage} ) {
|
|
|
|
# otherwise use default language
|
|
$PreferredLanguage = $DefaultLanguage;
|
|
|
|
# if no message exists in default language, then take the first available language
|
|
if ( !$Param{Message}->{Customer}->{$PreferredLanguage} ) {
|
|
my @Languages = sort keys %{ $Param{Message}->{Customer} };
|
|
$PreferredLanguage = $Languages[0];
|
|
}
|
|
}
|
|
|
|
my $Notification = $Param{Message}->{Customer}->{$PreferredLanguage};
|
|
return if !$Notification;
|
|
|
|
# do text/plain to text/html convert
|
|
if ( $Self->{RichText} && $Notification->{ContentType} =~ m{ text/plain }xmsi ) {
|
|
$Notification->{ContentType} = 'text/html';
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $Notification->{Body},
|
|
);
|
|
}
|
|
|
|
# do text/html to text/plain convert
|
|
elsif ( !$Self->{RichText} && $Notification->{ContentType} =~ m{ text/html }xmsi ) {
|
|
$Notification->{ContentType} = 'text/plain';
|
|
$Notification->{Body} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToAscii(
|
|
String => $Notification->{Body},
|
|
);
|
|
}
|
|
|
|
# replace otrs macros
|
|
$Notification->{Body} = $Self->_NotificationReplaceMacros(
|
|
Type => $Param{Type},
|
|
Text => $Notification->{Body},
|
|
Recipient => {%CustomerUser},
|
|
RichText => $Self->{RichText},
|
|
UserID => $Param{UserID},
|
|
Change => $Change,
|
|
WorkOrder => $WorkOrder,
|
|
Link => $Link,
|
|
Data => $Param{Data},
|
|
Language => $PreferredLanguage,
|
|
);
|
|
|
|
$Notification->{Subject} = $Self->_NotificationReplaceMacros(
|
|
Type => $Param{Type},
|
|
Text => $Notification->{Subject},
|
|
Recipient => {%CustomerUser},
|
|
UserID => $Param{UserID},
|
|
Change => $Change,
|
|
WorkOrder => $WorkOrder,
|
|
Link => $Link,
|
|
Data => $Param{Data},
|
|
Language => $PreferredLanguage,
|
|
);
|
|
|
|
# send notification
|
|
$Kernel::OM->Get('Kernel::System::Email')->Send(
|
|
From => $Kernel::OM->Get('Kernel::Config')->Get('NotificationSenderName') . ' <'
|
|
. $Kernel::OM->Get('Kernel::Config')->Get('NotificationSenderEmail') . '>',
|
|
To => $CustomerUser{UserEmail},
|
|
Subject => $Notification->{Subject},
|
|
MimeType => $Notification->{ContentType} || 'text/plain',
|
|
Charset => 'utf-8',
|
|
Body => $Notification->{Body},
|
|
Loop => 1,
|
|
);
|
|
|
|
# trigger NotificationSent-Event
|
|
my ($Type) = $Event =~ m{ (WorkOrder|Change) }xms;
|
|
$Self->EventHandler(
|
|
Event => $Type . 'NotificationSentPost',
|
|
Data => {
|
|
WorkOrderID => $WorkOrder->{WorkOrderID},
|
|
ChangeID => $Change->{ChangeID},
|
|
EventType => $Event,
|
|
To => $CustomerUser{UserEmail},
|
|
},
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
$CustomersSent{$CustomerID} = 1;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 NotificationRuleGet()
|
|
|
|
Get info about a single notification rule
|
|
|
|
my $NotificationRule = $NotificationObject->NotificationRuleGet(
|
|
ID => 123,
|
|
);
|
|
|
|
returns
|
|
|
|
{
|
|
ID => 123,
|
|
Name => 'a descriptive name',
|
|
Attribute => 'ChangeTitle',
|
|
EventID => 1,
|
|
Event => 'ChangeUpdate',
|
|
ValidID => 1,
|
|
Comment => 'description what the rule does',
|
|
Rule => 'rejected',
|
|
Recipients => [ 'ChangeBuilder', 'ChangeManager', 'ChangeCABCustomers' ],
|
|
RecipientIDs => [ 2, 3, 7 ],
|
|
Message => {
|
|
Agent => {
|
|
'en' => {
|
|
Subject => 'Hello Agent',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Agent',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
Customer => {
|
|
'en' => {
|
|
Subject => 'Hello Customer',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Kunde',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleGet {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need ID!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check the cache
|
|
my $CacheKey = 'NotificationRuleGet::ID::' . $Param{ID};
|
|
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
CacheInMemory => 1,
|
|
CacheInBackend => 0,
|
|
);
|
|
|
|
# return a clone of the cache, as the caller should not be able to change the cache
|
|
return Storable::dclone($Cache) if $Cache;
|
|
|
|
# do sql query
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT cn.id, cn.name, item_attribute, event_id, cht.name,
|
|
cn.valid_id, cn.comments, notification_rule
|
|
FROM change_notification cn, change_history_type cht
|
|
WHERE event_id = cht.id AND cn.id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch notification rule
|
|
my %NotificationRule;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
%NotificationRule = (
|
|
ID => $Row[0],
|
|
Name => $Row[1],
|
|
Attribute => $Row[2] // '',
|
|
EventID => $Row[3],
|
|
Event => $Row[4],
|
|
ValidID => $Row[5],
|
|
Comment => $Row[6],
|
|
Rule => $Row[7] // '',
|
|
Recipients => undef,
|
|
RecipientIDs => undef,
|
|
);
|
|
}
|
|
|
|
# get additional info
|
|
if (%NotificationRule) {
|
|
|
|
# get recipients
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT grp.id, grp.name
|
|
FROM change_notification_grps grp, change_notification_rec r
|
|
WHERE grp.id = r.group_id AND r.notification_id = ?',
|
|
Bind => [ \$NotificationRule{ID} ],
|
|
);
|
|
|
|
# fetch recipients
|
|
my @Recipients;
|
|
my @RecipientIDs;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
push @RecipientIDs, $Row[0];
|
|
push @Recipients, $Row[1];
|
|
}
|
|
|
|
$NotificationRule{Recipients} = \@Recipients;
|
|
$NotificationRule{RecipientIDs} = \@RecipientIDs;
|
|
|
|
# get change notification message data
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT subject, text, content_type, language, notification_type
|
|
FROM change_notification_message
|
|
WHERE notification_id = ?',
|
|
Bind => [ \$NotificationRule{ID} ],
|
|
);
|
|
|
|
my %Message;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
|
|
# add to message hash with the notification type and the language as key
|
|
# e.g. $Message{Agent}->{de}, or $Message{Customer}->{en}
|
|
$Message{ $Row[4] }->{ $Row[3] } = {
|
|
Subject => $Row[0],
|
|
Body => $Row[1],
|
|
ContentType => $Row[2],
|
|
};
|
|
}
|
|
|
|
$NotificationRule{Message} = \%Message;
|
|
}
|
|
|
|
# save values in cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Set(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
|
|
# make a local copy of the notification data to avoid it being altered in-memory later
|
|
Value => {%NotificationRule},
|
|
|
|
CacheInMemory => 1,
|
|
CacheInBackend => 0,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
# return a clone of the cache, as the caller should not be able to change the cache
|
|
return Storable::dclone( \%NotificationRule );
|
|
}
|
|
|
|
=head2 NotificationRuleAdd()
|
|
|
|
Add a notification rule. Returns the ID of the rule.
|
|
|
|
my $ID = $NotificationObject->NotificationRuleAdd(
|
|
Name => 'a descriptive name',
|
|
Attribute => 'ChangeTitle',
|
|
EventID => 1,
|
|
ValidID => 1,
|
|
Comment => 'description what the rule does',
|
|
Rule => 'rejected',
|
|
RecipientIDs => [ 2, 3, 7 ],
|
|
Message => {
|
|
Agent => {
|
|
'en' => {
|
|
Subject => 'Hello Agent',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Agent',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
Customer => {
|
|
'en' => {
|
|
Subject => 'Hello Customer',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Kunde',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
},
|
|
);
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleAdd {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(Name EventID ValidID RecipientIDs Message)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# RecipientIDs must be an array reference
|
|
if ( ref $Param{RecipientIDs} ne 'ARRAY' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'RecipientIDs must be an array reference!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check message
|
|
for my $Type (qw(Agent Customer)) {
|
|
|
|
# check message parameter, we always need agent and message
|
|
if ( !IsHashRefWithData( $Param{Message}->{$Type} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check each argument for each message language
|
|
for my $Language ( sort keys %{ $Param{Message}->{$Type} } ) {
|
|
|
|
for my $Argument (qw(Subject Body ContentType)) {
|
|
|
|
# error if message data is incomplete
|
|
if ( !$Param{Message}->{$Type}->{$Language}->{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message argument '$Argument' for language '$Language'!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# fix some bad stuff from some browsers (Opera)!
|
|
$Param{Message}->{$Type}->{$Language}->{Body} =~ s/(\n\r|\r\r\n|\r\n|\r)/\n/g;
|
|
}
|
|
}
|
|
|
|
# save notification rule
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO change_notification
|
|
(name, event_id, valid_id, item_attribute, comments, notification_rule)
|
|
VALUES (?, ?, ?, ?, ?, ?)',
|
|
Bind => [
|
|
\$Param{Name}, \$Param{EventID}, \$Param{ValidID},
|
|
\$Param{Attribute}, \$Param{Comment}, \$Param{Rule},
|
|
],
|
|
);
|
|
|
|
# get ID of rule
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT id
|
|
FROM change_notification
|
|
WHERE name = ?
|
|
AND event_id = ?
|
|
AND valid_id = ?
|
|
AND item_attribute = ?
|
|
AND comments = ?
|
|
AND notification_rule = ?',
|
|
Bind => [
|
|
\$Param{Name}, \$Param{EventID}, \$Param{ValidID},
|
|
\$Param{Attribute}, \$Param{Comment}, \$Param{Rule},
|
|
],
|
|
Limit => 1,
|
|
);
|
|
|
|
# fetch ID
|
|
my $RuleID;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$RuleID = $Row[0];
|
|
}
|
|
|
|
return if !$RuleID;
|
|
|
|
# insert recipients
|
|
for my $RecipientID ( @{ $Param{RecipientIDs} } ) {
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO change_notification_rec (notification_id, group_id) VALUES (?, ?)',
|
|
Bind => [ \$RuleID, \$RecipientID ],
|
|
);
|
|
}
|
|
|
|
# insert change notification message data
|
|
for my $Type (qw(Agent Customer)) {
|
|
|
|
for my $Language ( sort keys %{ $Param{Message}->{$Type} } ) {
|
|
|
|
my %Message = %{ $Param{Message}->{$Type}->{$Language} };
|
|
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO change_notification_message
|
|
(notification_id, subject, text, content_type, language, notification_type)
|
|
VALUES (?, ?, ?, ?, ?, ?)',
|
|
Bind => [
|
|
\$RuleID,
|
|
\$Message{Subject},
|
|
\$Message{Body},
|
|
\$Message{ContentType},
|
|
\$Language,
|
|
\$Type,
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
# delete cache
|
|
for my $Key (
|
|
'NotificationRuleList',
|
|
'NotificationRuleSearch::Valid::0',
|
|
'NotificationRuleSearch::Valid::1',
|
|
'NotificationRuleSearch::Valid::0::EventID::' . $Param{EventID},
|
|
'NotificationRuleSearch::Valid::1::EventID::' . $Param{EventID},
|
|
)
|
|
{
|
|
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $Key,
|
|
);
|
|
}
|
|
|
|
return $RuleID;
|
|
}
|
|
|
|
=head2 NotificationRuleUpdate()
|
|
|
|
Updates an existing notification rule.
|
|
|
|
my $Success = $NotificationObject->NotificationRuleUpdate(
|
|
ID => 123,
|
|
Name => 'a descriptive name',
|
|
Attribute => 'ChangeTitle',
|
|
EventID => 1,
|
|
ValidID => 1,
|
|
Comment => 'description what the rule does',
|
|
Rule => 'rejected',
|
|
RecipientIDs => [ 2, 3, 7 ],
|
|
Message => {
|
|
Agent => {
|
|
'en' => {
|
|
Subject => 'Hello Agent',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Agent',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
Customer => {
|
|
'en' => {
|
|
Subject => 'Hello Customer',
|
|
Body => 'Hello World',
|
|
ContentType => 'text/plain',
|
|
},
|
|
'de' => {
|
|
Subject => 'Hallo Kunde',
|
|
Body => 'Hallo Welt',
|
|
ContentType => 'text/plain',
|
|
},
|
|
},
|
|
},
|
|
);
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleUpdate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(ID Name EventID ValidID RecipientIDs Message)) {
|
|
if ( !$Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# RecipientIDs must be an array reference
|
|
if ( ref $Param{RecipientIDs} ne 'ARRAY' ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'RecipientIDs must be an array reference!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check message
|
|
for my $Type (qw(Agent Customer)) {
|
|
|
|
# check message parameter, we always need agent and message
|
|
if ( !IsHashRefWithData( $Param{Message}->{$Type} ) ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check each argument for each message language
|
|
for my $Language ( sort keys %{ $Param{Message}->{$Type} } ) {
|
|
|
|
for my $Argument (qw(Subject Body ContentType)) {
|
|
|
|
# error if message data is incomplete
|
|
if ( !$Param{Message}->{$Type}->{$Language}->{$Argument} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Type Message argument '$Argument' for language '$Language'!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
# fix some bad stuff from some browsers (Opera)!
|
|
$Param{Message}->{$Type}->{$Language}->{Body} =~ s/(\n\r|\r\r\n|\r\n|\r)/\n/g;
|
|
}
|
|
}
|
|
|
|
# save notification rule
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'UPDATE change_notification '
|
|
. 'SET name = ?, event_id = ?, valid_id = ?, item_attribute = ?, '
|
|
. 'comments = ?, notification_rule = ? WHERE id = ?',
|
|
Bind => [
|
|
\$Param{Name}, \$Param{EventID}, \$Param{ValidID},
|
|
\$Param{Attribute}, \$Param{Comment}, \$Param{Rule},
|
|
\$Param{ID},
|
|
],
|
|
);
|
|
|
|
# delete old recipient entries
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM change_notification_rec WHERE notification_id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# insert recipients
|
|
for my $RecipientID ( @{ $Param{RecipientIDs} } ) {
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO change_notification_rec (notification_id, group_id) VALUES (?, ?)',
|
|
Bind => [ \$Param{ID}, \$RecipientID ],
|
|
);
|
|
}
|
|
|
|
# delete old change notification message data
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM change_notification_message WHERE notification_id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# insert change notification message data
|
|
for my $Type (qw(Agent Customer)) {
|
|
|
|
for my $Language ( sort keys %{ $Param{Message}->{$Type} } ) {
|
|
|
|
my %Message = %{ $Param{Message}->{$Type}->{$Language} };
|
|
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'INSERT INTO change_notification_message
|
|
(notification_id, subject, text, content_type, language, notification_type)
|
|
VALUES (?, ?, ?, ?, ?, ?)',
|
|
Bind => [
|
|
\$Param{ID},
|
|
\$Message{Subject},
|
|
\$Message{Body},
|
|
\$Message{ContentType},
|
|
\$Language,
|
|
\$Type,
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
# delete cache
|
|
for my $Key (
|
|
'NotificationRuleGet::ID::' . $Param{ID},
|
|
'NotificationRuleList',
|
|
'NotificationRuleSearch::Valid::0',
|
|
'NotificationRuleSearch::Valid::1',
|
|
'NotificationRuleSearch::Valid::0::EventID::' . $Param{EventID},
|
|
'NotificationRuleSearch::Valid::1::EventID::' . $Param{EventID},
|
|
)
|
|
{
|
|
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Delete(
|
|
Type => $Self->{CacheType},
|
|
Key => $Key,
|
|
);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 NotificationRuleDelete()
|
|
|
|
deletes an existing notification rule
|
|
|
|
my $Success = $NotificationObject->NotificationRuleDelete(
|
|
ID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleDelete {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need ID!",
|
|
);
|
|
return;
|
|
}
|
|
|
|
# delete change notification recipient entries
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM change_notification_rec WHERE notification_id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# delete change notification message data
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM change_notification_message WHERE notification_id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# delete change notification
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
|
SQL => 'DELETE FROM change_notification WHERE id = ?',
|
|
Bind => [ \$Param{ID} ],
|
|
);
|
|
|
|
# cleanup cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->CleanUp(
|
|
Type => $Self->{CacheType},
|
|
);
|
|
|
|
return 1;
|
|
}
|
|
|
|
=head2 NotificationRuleList()
|
|
|
|
returns an array reference with IDs of all existing notification rules
|
|
|
|
my $List = $NotificationObject->NotificationRuleList();
|
|
|
|
returns
|
|
|
|
[ 1, 2, 3 ]
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleList {
|
|
my $Self = shift;
|
|
|
|
# check the cache
|
|
my $CacheKey = 'NotificationRuleList';
|
|
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
return $Cache if $Cache;
|
|
|
|
# do sql query,
|
|
# sort in a userfriendly fashion
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT id FROM change_notification '
|
|
. 'ORDER BY event_id, item_attribute, notification_rule',
|
|
);
|
|
|
|
# fetch IDs
|
|
my @IDs;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
push @IDs, $Row[0];
|
|
}
|
|
|
|
# save values in cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Set(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
Value => \@IDs,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return \@IDs;
|
|
}
|
|
|
|
=head2 NotificationRuleSearch()
|
|
|
|
Returns an array reference with IDs of all matching notification rules.
|
|
The only valid search parameter is the EventID.
|
|
|
|
my $NotificationRuleIDs = $NotificationObject->NotificationRuleSearch(
|
|
EventID => 4, # optional, primary key in change_history_type
|
|
Valid => 1, # optional, default is 1
|
|
);
|
|
|
|
returns
|
|
|
|
[ 1, 2, 3 ]
|
|
|
|
=cut
|
|
|
|
sub NotificationRuleSearch {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Valid = defined $Param{Valid} ? $Param{Valid} : 1;
|
|
|
|
my @SQLWhere; # assemble the conditions used in the WHERE clause
|
|
my @SQLBind; # parameters for the WHERE clause
|
|
|
|
# define the cache key
|
|
my $CacheKey = 'NotificationRuleSearch::Valid::' . $Valid;
|
|
|
|
# for now we only have a single search param
|
|
if ( $Param{EventID} ) {
|
|
push @SQLWhere, 'cn.event_id = ?';
|
|
push @SQLBind, \$Param{EventID};
|
|
$CacheKey .= '::EventID::' . $Param{EventID};
|
|
}
|
|
|
|
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
return $Cache if $Cache;
|
|
|
|
my $SQL = 'SELECT id FROM change_notification cn ';
|
|
|
|
# add the WHERE clause
|
|
if (@SQLWhere) {
|
|
$SQL .= 'WHERE ';
|
|
$SQL .= join ' AND ', map {"( $_ )"} @SQLWhere;
|
|
$SQL .= ' ';
|
|
}
|
|
|
|
# add valid option
|
|
if ($Valid) {
|
|
$SQL .= 'AND cn.valid_id IN ('
|
|
. join( ', ', $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet() ) . ') ';
|
|
}
|
|
|
|
# add the ORDER BY clause
|
|
$SQL .= 'ORDER BY cn.id ';
|
|
|
|
# do sql query
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => $SQL,
|
|
Bind => \@SQLBind,
|
|
);
|
|
|
|
# fetch IDs
|
|
my @IDs;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
push @IDs, $Row[0];
|
|
}
|
|
|
|
# save values in cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Set(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
Value => \@IDs,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return \@IDs;
|
|
}
|
|
|
|
=head2 RecipientLookup()
|
|
|
|
Returns the ID when you pass the recipient name and returns the name if you
|
|
pass the recipient ID.
|
|
|
|
my $ID = $NotificationObject->RecipientLookup(
|
|
Name => 'ChangeBuilder',
|
|
);
|
|
|
|
my $Name = $NotificationObject->RecipientLookup(
|
|
ID => 123,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub RecipientLookup {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
if ( !$Param{ID} && !$Param{Name} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need either ID or Name!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
if ( $Param{ID} && $Param{Name} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => 'Need either ID or Name - not both!',
|
|
);
|
|
return;
|
|
}
|
|
|
|
# check the cache
|
|
my $CacheKey;
|
|
if ( $Param{ID} ) {
|
|
$CacheKey = 'RecipientLookup::ID::' . $Param{ID};
|
|
}
|
|
elsif ( $Param{Name} ) {
|
|
$CacheKey = 'RecipientLookup::Name::' . $Param{Name};
|
|
}
|
|
my $Cache = $Kernel::OM->Get('Kernel::System::Cache')->Get(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
);
|
|
return $Cache if $Cache;
|
|
|
|
# determine sql statement and bind parameters
|
|
my $SQL;
|
|
my @Binds;
|
|
if ( $Param{ID} ) {
|
|
$SQL = 'SELECT name FROM change_notification_grps WHERE id = ?';
|
|
@Binds = ( \$Param{ID} );
|
|
}
|
|
elsif ( $Param{Name} ) {
|
|
$SQL = 'SELECT id FROM change_notification_grps WHERE name = ?';
|
|
@Binds = ( \$Param{Name} );
|
|
}
|
|
|
|
# do sql query
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => $SQL,
|
|
Bind => \@Binds,
|
|
Limit => 1,
|
|
);
|
|
|
|
# get value
|
|
my $Value;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
$Value = $Row[0];
|
|
}
|
|
|
|
# save value in cache
|
|
$Kernel::OM->Get('Kernel::System::Cache')->Set(
|
|
Type => $Self->{CacheType},
|
|
Key => $CacheKey,
|
|
Value => $Value,
|
|
TTL => $Self->{CacheTTL},
|
|
);
|
|
|
|
return $Value;
|
|
}
|
|
|
|
=head2 RecipientList()
|
|
|
|
Returns an array reference with hash references. The key of the hash reference is the id
|
|
of an recipient and the human readable and translatable name is the value.
|
|
|
|
my $List = $NotificationObject->RecipientList();
|
|
|
|
returns
|
|
|
|
[
|
|
{
|
|
Key => 1,
|
|
Value => 'Change Builder',
|
|
},
|
|
{
|
|
Key => 2,
|
|
Value => 'Change Manager',
|
|
},
|
|
]
|
|
|
|
=cut
|
|
|
|
sub RecipientList {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# Human readable translatable names of recipients.
|
|
my %HumanReadableRecipient = (
|
|
ChangeBuilder => Translatable('Change Builder'),
|
|
OldChangeBuilder => Translatable('Previous Change Builder'),
|
|
ChangeManager => Translatable('Change Manager'),
|
|
OldChangeManager => Translatable('Previous Change Manager'),
|
|
CABCustomers => Translatable('CAB Customers'),
|
|
CABAgents => Translatable('CAB Agents'),
|
|
WorkOrderAgents => Translatable('Workorder Agents'),
|
|
WorkOrderAgent => Translatable('Workorder Agent'),
|
|
OldWorkOrderAgent => Translatable('Previous Workorder Agent'),
|
|
ChangeInitiators => Translatable('Change Initiators'),
|
|
GroupITSMChange => Translatable('Group ITSMChange'),
|
|
GroupITSMChangeBuilder => Translatable('Group ITSMChangeBuilder'),
|
|
GroupITSMChangeManager => Translatable('Group ITSMChangeManager'),
|
|
);
|
|
|
|
# do SQL query
|
|
return if !$Kernel::OM->Get('Kernel::System::DB')->Prepare(
|
|
SQL => 'SELECT id, name
|
|
FROM change_notification_grps
|
|
ORDER BY name',
|
|
);
|
|
|
|
# fetch recipients
|
|
my @Recipients;
|
|
while ( my @Row = $Kernel::OM->Get('Kernel::System::DB')->FetchrowArray() ) {
|
|
my $Recipient = {
|
|
Key => $Row[0],
|
|
Value => $HumanReadableRecipient{ $Row[1] } || $Row[1],
|
|
};
|
|
push @Recipients, $Recipient;
|
|
}
|
|
|
|
return \@Recipients;
|
|
}
|
|
|
|
=begin Internal:
|
|
|
|
=head2 _NotificationReplaceMacros()
|
|
|
|
This method replaces all the <OTRS_xxxx> macros in notification text.
|
|
|
|
my $CleanText = $NotificationObject->_NotificationReplaceMacros(
|
|
Type => 'Change', # Change|WorkOrder
|
|
Text => 'Some <OTRS_CONFIG_FQDN> text',
|
|
RichText => 1, # optional, is Text richtext or not. default 0
|
|
Recipient => {%User},
|
|
Data => {
|
|
ChangeBuilder => {
|
|
UserFirstname => 'Tom',
|
|
UserLastname => 'Tester',
|
|
UserEmail => 'tt@otrs.com',
|
|
},
|
|
},
|
|
Change => $Change,
|
|
WorkOrder => $WorkOrder,
|
|
Link => $Link,
|
|
Language => $Language, # used for translating states and such
|
|
UserID => 1,
|
|
);
|
|
|
|
=cut
|
|
|
|
sub _NotificationReplaceMacros {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
# check needed stuff
|
|
for my $Needed (qw(Type Text Data UserID Change WorkOrder Link Language)) {
|
|
if ( !defined $Param{$Needed} ) {
|
|
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
|
Priority => 'error',
|
|
Message => "Need $Needed!",
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
my $Text = $Param{Text};
|
|
|
|
# determine what "macro" delimiters are used
|
|
my $Start = '<';
|
|
my $End = '>';
|
|
|
|
# with richtext enabled, the delimiters change
|
|
if ( $Param{RichText} ) {
|
|
$Start = '<';
|
|
$End = '>';
|
|
$Text =~ s{ (\n|\r) }{}xmsg;
|
|
}
|
|
|
|
# translate Change and Workorder values, where appropriate
|
|
# we need to create a new language object manually (without the object manager),
|
|
# so we can translate into the language of the recipient
|
|
my $LanguageObject = Kernel::Language->new(
|
|
UserLanguage => $Param{Language},
|
|
);
|
|
my %ChangeData = %{ $Param{Change} };
|
|
for my $Field (qw(ChangeState Category Priority Impact)) {
|
|
$ChangeData{$Field} = $LanguageObject->Translate( $ChangeData{$Field} );
|
|
}
|
|
|
|
my %WorkOrderData = %{ $Param{WorkOrder} };
|
|
for my $Field (qw(WorkOrderState WorkOrderType)) {
|
|
$WorkOrderData{$Field} = $LanguageObject->Translate( $WorkOrderData{$Field} );
|
|
}
|
|
|
|
# replace config options
|
|
my $Tag = $Start . 'OTRS_CONFIG_';
|
|
$Text =~ s{ $Tag (.+?) $End }{$Kernel::OM->Get('Kernel::Config')->Get($1)}egx;
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End }{-}gi;
|
|
|
|
$Tag = $Start . 'OTRS_Agent_';
|
|
my $Tag2 = $Start . 'OTRS_CURRENT_';
|
|
my %CurrentUser = $Kernel::OM->Get('Kernel::System::User')->GetUserData( UserID => $Param{UserID} );
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %CurrentUser ) {
|
|
next KEY if !$CurrentUser{$Key};
|
|
$CurrentUser{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $CurrentUser{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %CurrentUser ) {
|
|
next KEY if !defined $CurrentUser{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$CurrentUser{$Key}}gxmsi;
|
|
$Text =~ s{ $Tag2 $Key $End }{$CurrentUser{$Key}}gxmsi;
|
|
}
|
|
|
|
# replace other needed stuff
|
|
$Text =~ s{ $Start OTRS_FIRST_NAME $End }{$CurrentUser{UserFirstname}}gxms;
|
|
$Text =~ s{ $Start OTRS_LAST_NAME $End }{$CurrentUser{UserLastname}}gxms;
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}xmsgi;
|
|
$Text =~ s{ $Tag2 .+? $End}{-}xmsgi;
|
|
|
|
# get and prepare realname
|
|
$Tag = $Start . 'OTRS_CUSTOMER_REALNAME';
|
|
$Text =~ s{$Tag$End}{-}g;
|
|
|
|
# get customer data and replace it with <OTRS_CUSTOMER_DATA_...
|
|
$Tag = $Start . 'OTRS_CUSTOMER_';
|
|
$Tag2 = $Start . 'OTRS_CUSTOMER_DATA_';
|
|
|
|
# cleanup all not needed <OTRS_CUSTOMER_DATA_ tags
|
|
$Text =~ s{ $Tag .+? $End }{-}xmsgi;
|
|
$Text =~ s{ $Tag2 .+? $End}{-}xmsgi;
|
|
|
|
# get dynamic field objects
|
|
my $DynamicFieldObject = $Kernel::OM->Get('Kernel::System::DynamicField');
|
|
my $DynamicFieldBackendObject = $Kernel::OM->Get('Kernel::System::DynamicField::Backend');
|
|
|
|
# replace <OTRS_CHANGE_... tags
|
|
{
|
|
my $Tag = $Start . 'OTRS_CHANGE_';
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %ChangeData ) {
|
|
next KEY if !$ChangeData{$Key};
|
|
$ChangeData{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $ChangeData{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# get change builder and change manager
|
|
USER:
|
|
for my $User (qw(ChangeBuilder ChangeManager)) {
|
|
|
|
my $Attribute = $User . 'ID';
|
|
|
|
# only if an agent is set for this attribute
|
|
next USER if !$ChangeData{$Attribute};
|
|
|
|
# get user data
|
|
my %UserData = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $ChangeData{$Attribute},
|
|
Valid => 1,
|
|
);
|
|
|
|
next USER if !%UserData;
|
|
|
|
# build user attribute
|
|
$ChangeData{$User} = "$UserData{UserFullname}";
|
|
}
|
|
|
|
# Dropdown, Checkbox and MultipleSelect DynamicFields, can store values (keys) that are
|
|
# different from the the values to display
|
|
# <OTRS_CHANGE_DynamicField_NameX> returns the stored key
|
|
# <OTRS_CHANGE_DynamicField_NameX_Value> returns the display value
|
|
|
|
# get the dynamic fields for change object
|
|
my $DynamicFieldList = $DynamicFieldObject->DynamicFieldListGet(
|
|
Valid => 1,
|
|
ObjectType => ['ITSMChange'],
|
|
) || [];
|
|
|
|
# cycle through all change Dynamic Fields
|
|
DYNAMICFIELD:
|
|
for my $DynamicFieldConfig ( @{$DynamicFieldList} ) {
|
|
|
|
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
|
|
|
# get the display value for each dynamic field
|
|
my $DisplayValue = $DynamicFieldBackendObject->ValueLookup(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Key => $ChangeData{ 'DynamicField_' . $DynamicFieldConfig->{Name} },
|
|
LanguageObject => $LanguageObject,
|
|
);
|
|
|
|
# get the readable value (value) for each dynamic field
|
|
my $DisplayValueStrg = $DynamicFieldBackendObject->ReadableValueRender(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Value => $DisplayValue,
|
|
);
|
|
|
|
# fill the DynamicFielsDisplayValues
|
|
if ($DisplayValueStrg) {
|
|
$ChangeData{ 'DynamicField_' . $DynamicFieldConfig->{Name} . '_Value' } = $DisplayValueStrg->{Value};
|
|
}
|
|
|
|
# get the readable value (key) for each dynamic field
|
|
my $ValueStrg = $DynamicFieldBackendObject->ReadableValueRender(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Value => $ChangeData{ 'DynamicField_' . $DynamicFieldConfig->{Name} },
|
|
);
|
|
|
|
# replace ticket content with the value from ReadableValueRender (if any)
|
|
if ( IsHashRefWithData($ValueStrg) ) {
|
|
$ChangeData{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = $ValueStrg->{Value};
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %ChangeData ) {
|
|
next KEY if !defined $ChangeData{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$ChangeData{$Key}}gxmsi;
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
}
|
|
|
|
# replace <OTRS_WORKORDER_... tags
|
|
{
|
|
my $Tag = $Start . 'OTRS_WORKORDER_';
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %WorkOrderData ) {
|
|
next KEY if !$WorkOrderData{$Key};
|
|
$WorkOrderData{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $WorkOrderData{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# get workorder agent
|
|
if ( $WorkOrderData{WorkOrderAgentID} ) {
|
|
|
|
# get user data
|
|
my %UserData = $Kernel::OM->Get('Kernel::System::User')->GetUserData(
|
|
UserID => $WorkOrderData{WorkOrderAgentID},
|
|
Valid => 1,
|
|
);
|
|
|
|
# build workorder agent attribute
|
|
if (%UserData) {
|
|
$WorkOrderData{WorkOrderAgent} = "$UserData{UserFullname}";
|
|
}
|
|
}
|
|
|
|
# Dropdown, Checkbox and MultipleSelect DynamicFields, can store values (keys) that are
|
|
# different from the the values to display
|
|
# <OTRS_WORKORDER_DynamicField_NameX> returns the stored key
|
|
# <OTRS_WORKORDER_DynamicField_NameX_Value> returns the display value
|
|
|
|
# get the dynamic fields for workorder object
|
|
my $DynamicFieldList = $DynamicFieldObject->DynamicFieldListGet(
|
|
Valid => 1,
|
|
ObjectType => ['ITSMWorkOrder'],
|
|
) || [];
|
|
|
|
# cycle through all workorder Dynamic Fields
|
|
DYNAMICFIELD:
|
|
for my $DynamicFieldConfig ( @{$DynamicFieldList} ) {
|
|
|
|
next DYNAMICFIELD if !IsHashRefWithData($DynamicFieldConfig);
|
|
|
|
# get the display value for each dynamic field
|
|
my $DisplayValue = $DynamicFieldBackendObject->ValueLookup(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Key => $WorkOrderData{ 'DynamicField_' . $DynamicFieldConfig->{Name} },
|
|
LanguageObject => $LanguageObject,
|
|
);
|
|
|
|
# get the readable value (value) for each dynamic field
|
|
my $DisplayValueStrg = $DynamicFieldBackendObject->ReadableValueRender(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Value => $DisplayValue,
|
|
);
|
|
|
|
# fill the DynamicFielsDisplayValues
|
|
if ($DisplayValueStrg) {
|
|
$WorkOrderData{ 'DynamicField_' . $DynamicFieldConfig->{Name} . '_Value' } = $DisplayValueStrg->{Value};
|
|
}
|
|
|
|
# get the readable value (key) for each dynamic field
|
|
my $ValueStrg = $DynamicFieldBackendObject->ReadableValueRender(
|
|
DynamicFieldConfig => $DynamicFieldConfig,
|
|
Value => $WorkOrderData{ 'DynamicField_' . $DynamicFieldConfig->{Name} },
|
|
);
|
|
|
|
# replace ticket content with the value from ReadableValueRender (if any)
|
|
if ( IsHashRefWithData($ValueStrg) ) {
|
|
$WorkOrderData{ 'DynamicField_' . $DynamicFieldConfig->{Name} } = $ValueStrg->{Value};
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %WorkOrderData ) {
|
|
next KEY if !defined $WorkOrderData{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$WorkOrderData{$Key}}gxmsi;
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
}
|
|
|
|
# replace <OTRS_CONDITION... tags
|
|
{
|
|
my $Tag = $Start . 'OTRS_CONDITION_';
|
|
my %Data = %{ $Param{Data} };
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %Data ) {
|
|
next KEY if !$Data{$Key};
|
|
$Data{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $Data{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %Data ) {
|
|
next KEY if !defined $Data{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$Data{$Key}}gxmsi;
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
}
|
|
|
|
# replace <OTRS_LINK_... tags
|
|
{
|
|
my $Tag = $Start . 'OTRS_LINK_';
|
|
my %LinkData = %{ $Param{Link} };
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %LinkData ) {
|
|
next KEY if !$LinkData{$Key};
|
|
$LinkData{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $LinkData{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %LinkData ) {
|
|
next KEY if !defined $LinkData{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$LinkData{$Key}}gxmsi;
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
}
|
|
|
|
# replace extended <OTRS_CHANGE_... tags
|
|
my %InfoHash = %{ $Param{Data} };
|
|
|
|
for my $Object (qw(ChangeBuilder ChangeManager WorkOrderAgent)) {
|
|
my $Tag = $Start . uc 'OTRS_' . $Object . '_';
|
|
|
|
if ( exists $InfoHash{$Object} && ref $InfoHash{$Object} eq 'HASH' ) {
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
|
|
KEY:
|
|
for my $Key ( sort keys %{ $InfoHash{$Object} } ) {
|
|
next KEY if !$InfoHash{$Object}->{$Key};
|
|
$InfoHash{$Object}->{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $InfoHash{$Object}->{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %{ $InfoHash{$Object} } ) {
|
|
next KEY if !defined $InfoHash{$Object}->{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$InfoHash{$Object}->{$Key}}gxmsi;
|
|
}
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
}
|
|
|
|
# get recipient data and replace it with <OTRS_...
|
|
$Tag = $Start . 'OTRS_';
|
|
if ( $Param{Recipient} ) {
|
|
|
|
# html quoting of content
|
|
if ( $Param{RichText} ) {
|
|
KEY:
|
|
for my $Key ( sort keys %{ $Param{Recipient} } ) {
|
|
next KEY if !$Param{Recipient}->{$Key};
|
|
$Param{Recipient}->{$Key} = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToHTML(
|
|
String => $Param{Recipient}->{$Key},
|
|
);
|
|
}
|
|
}
|
|
|
|
# replace it
|
|
KEY:
|
|
for my $Key ( sort keys %{ $Param{Recipient} } ) {
|
|
next KEY if !defined $Param{Recipient}->{$Key};
|
|
my $Value = $Param{Recipient}->{$Key};
|
|
$Text =~ s{ $Tag $Key $End }{$Value}gxmsi;
|
|
}
|
|
}
|
|
|
|
# cleanup
|
|
$Text =~ s{ $Tag .+? $End}{-}gxmsi;
|
|
|
|
return $Text;
|
|
}
|
|
|
|
1;
|
|
|
|
=end Internal:
|
|
|
|
=head2 The following placeholders can be used in Change::xxx notifications
|
|
|
|
=head3 C<OTRS_CHANGE_xxx>
|
|
|
|
with the subsequent values for xxx:
|
|
|
|
ChangeID
|
|
The ID of the change
|
|
ChangeNumber
|
|
The number of the change
|
|
ChangeStateID
|
|
The ID of the change state
|
|
ChangeState
|
|
The name of the change state (e.g. requested, approved)
|
|
ChangeStateSignal
|
|
ChangeTitle
|
|
The change title
|
|
Description
|
|
The "original" description. Please note: If richtext feature is enabled,
|
|
this contains HTML markup. So this can be used to send HTML notifications.
|
|
DescriptionPlain
|
|
This is the plain description without any HTML markup. This is better for plain notifications.
|
|
Justification
|
|
The same as for Description applies here.
|
|
JustificationPlain
|
|
See DescriptionPlain.
|
|
ChangeBuilderID
|
|
Change builder ID
|
|
ChangeManagerID
|
|
Change manager ID
|
|
CategoryID
|
|
ID of changes' category.
|
|
Category
|
|
Name of changes' category.
|
|
ImpactID
|
|
ID of changes' impact.
|
|
Impact
|
|
Name of changes' impact.
|
|
PriorityID
|
|
ID of changes' priority.
|
|
Priority
|
|
Name of changes' priority.
|
|
WorkOrderCount
|
|
Number of all work orders that belong to the change.
|
|
RequestedTime
|
|
The time the customer want the change to be finished.
|
|
PlannedEffort
|
|
Sum of the planned efforts (calculated from the workorders).
|
|
AccountedTime
|
|
Accounted time of the change (calculated from the workorders).
|
|
PlannedStartTime
|
|
Planned start time of the change (calculated from the workorders).
|
|
PlannedEndTime
|
|
Planned end time of the change (calculated from the workorders).
|
|
ActualStartTime
|
|
Actual start time of the change (calculated from the workorders).
|
|
ActualEndTime
|
|
Actual end time of the change (calculated from the workorders).
|
|
|
|
=head3 C<OTRS_CHANGEBUILDER_xxx>, C<OTRS_CHANGEMANAGER_xxx>, C<OTRS_WORKORDERAGENT_xxx>
|
|
|
|
with the subsequent values for xxx:
|
|
|
|
UserFirstname
|
|
Firstname of the person.
|
|
UserLastname
|
|
Lastname of the person.
|
|
UserEmail
|
|
Email address of the person.
|
|
|
|
=head3 C<OTRS_WORKORDER_xxx>
|
|
|
|
with the subsequent values for xxx:
|
|
|
|
WorkOrderID
|
|
ID of the workorder
|
|
ChangeID
|
|
ID of the change the workorder belongs to.
|
|
WorkOrderNumber
|
|
Workorder number
|
|
WorkOrderTitle
|
|
Title of the workorder
|
|
Instruction
|
|
See Change placeholders -> Description
|
|
InstructionPlain
|
|
See Change placeholders -> DescriptionPlain
|
|
Report
|
|
See Change placeholders -> Description
|
|
ReportPlain
|
|
See Change placeholders -> DescriptionPlain
|
|
WorkOrderStateID
|
|
ID of the workorder state.
|
|
WorkOrderState
|
|
Name of the workorder state.
|
|
WorkOrderStateSignal
|
|
WorkOrderTypeID
|
|
ID of the workorder type.
|
|
WorkOrderType
|
|
The name of the work order type.
|
|
WorkOrderAgentID
|
|
The ID of the workorder agent.
|
|
PlannedStartTime
|
|
The planned start time for the workorder.
|
|
PlannedEndTime
|
|
The planned end time for the workorder.
|
|
ActualStartTime
|
|
When did the workorder actually start.
|
|
ActualEndTime
|
|
When did the workorder actually end.
|
|
AccountedTime
|
|
The so far accounted time for the single workorder
|
|
PlannedEffort
|
|
This is the effort planned for the single workorder.
|
|
|
|
=head3 C<OTRS_LINK_xxx>
|
|
|
|
with the subsequent values for xxx:
|
|
|
|
Object
|
|
other object of the link
|
|
SourceObject
|
|
other object of the link, when the other object is the source
|
|
TargetObject
|
|
other object of the link, when the other object ist the target
|
|
State
|
|
State of the link
|
|
Type
|
|
Type of the link
|
|
|
|
=head1 TERMS AND CONDITIONS
|
|
|
|
This software is part of the OTRS project (L<https://otrs.org/>).
|
|
|
|
This software comes with ABSOLUTELY NO WARRANTY. For details, see
|
|
the enclosed file COPYING for license information (GPL). If you
|
|
did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
|
|
|
|
=cut
|