1731 lines
59 KiB
Perl
1731 lines
59 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::GenericInterface::Operation::Ticket::TicketCreate;
|
|
|
|
use strict;
|
|
use warnings;
|
|
|
|
use Kernel::System::VariableCheck qw(IsArrayRefWithData IsHashRefWithData IsString IsStringWithData);
|
|
|
|
use parent qw(
|
|
Kernel::GenericInterface::Operation::Common
|
|
Kernel::GenericInterface::Operation::Ticket::Common
|
|
);
|
|
|
|
our $ObjectManagerDisabled = 1;
|
|
|
|
=head1 NAME
|
|
|
|
Kernel::GenericInterface::Operation::Ticket::TicketCreate - GenericInterface Ticket TicketCreate Operation backend
|
|
|
|
=head1 PUBLIC INTERFACE
|
|
|
|
=head2 new()
|
|
|
|
usually, you want to create an instance of this
|
|
by using Kernel::GenericInterface::Operation->new();
|
|
|
|
=cut
|
|
|
|
sub new {
|
|
my ( $Type, %Param ) = @_;
|
|
|
|
my $Self = {};
|
|
bless( $Self, $Type );
|
|
|
|
# check needed objects
|
|
for my $Needed (qw( DebuggerObject WebserviceID )) {
|
|
if ( !$Param{$Needed} ) {
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => "Got no $Needed!",
|
|
};
|
|
}
|
|
|
|
$Self->{$Needed} = $Param{$Needed};
|
|
}
|
|
|
|
$Self->{Config} = $Kernel::OM->Get('Kernel::Config')->Get('GenericInterface::Operation::TicketCreate');
|
|
$Self->{Operation} = $Param{Operation};
|
|
|
|
return $Self;
|
|
}
|
|
|
|
=head2 Run()
|
|
|
|
perform TicketCreate Operation. This will return the created ticket number.
|
|
|
|
my $Result = $OperationObject->Run(
|
|
Data => {
|
|
UserLogin => 'some agent login', # UserLogin or CustomerUserLogin or SessionID is
|
|
# required
|
|
CustomerUserLogin => 'some customer login',
|
|
SessionID => 123,
|
|
|
|
Password => 'some password', # if UserLogin or CustomerUserLogin is sent then
|
|
# Password is required
|
|
|
|
Ticket => {
|
|
Title => 'some ticket title',
|
|
|
|
QueueID => 123, # QueueID or Queue is required
|
|
Queue => 'some queue name',
|
|
|
|
LockID => 123, # optional
|
|
Lock => 'some lock name', # optional
|
|
TypeID => 123, # optional
|
|
Type => 'some type name', # optional
|
|
ServiceID => 123, # optional
|
|
Service => 'some service name', # optional
|
|
SLAID => 123, # optional
|
|
SLA => 'some SLA name', # optional
|
|
|
|
StateID => 123, # StateID or State is required
|
|
State => 'some state name',
|
|
|
|
PriorityID => 123, # PriorityID or Priority is required
|
|
Priority => 'some priority name',
|
|
|
|
OwnerID => 123, # optional
|
|
Owner => 'some user login', # optional
|
|
ResponsibleID => 123, # optional
|
|
Responsible => 'some user login', # optional
|
|
CustomerUser => 'some customer user login',
|
|
|
|
PendingTime { # optional
|
|
Year => 2011,
|
|
Month => 12
|
|
Day => 03,
|
|
Hour => 23,
|
|
Minute => 05,
|
|
},
|
|
# or
|
|
# PendingTime {
|
|
# Diff => 10080, # Pending time in minutes
|
|
#},
|
|
},
|
|
Article => {
|
|
CommunicationChannel => 'Email', # CommunicationChannel or CommunicationChannelID must be provided.
|
|
CommunicationChannelID => 1,
|
|
IsVisibleForCustomer => 1, # optional
|
|
SenderTypeID => 123, # optional
|
|
SenderType => 'some sender type name', # optional
|
|
AutoResponseType => 'some auto response type', # optional
|
|
From => 'some from string', # optional
|
|
Subject => 'some subject',
|
|
Body => 'some body',
|
|
ContentType => 'some content type', # ContentType or MimeType and Charset is required
|
|
MimeType => 'some mime type',
|
|
Charset => 'some charset',
|
|
HistoryType => 'some history type', # optional
|
|
HistoryComment => 'Some history comment', # optional
|
|
TimeUnit => 123, # optional
|
|
NoAgentNotify => 1, # optional
|
|
ForceNotificationToUserID => [1, 2, 3] # optional
|
|
ExcludeNotificationToUserID => [1, 2, 3] # optional
|
|
ExcludeMuteNotificationToUserID => [1, 2, 3] # optional
|
|
},
|
|
|
|
DynamicField => [ # optional
|
|
{
|
|
Name => 'some name',
|
|
Value => $Value, # value type depends on the dynamic field
|
|
},
|
|
# ...
|
|
],
|
|
# or
|
|
# DynamicField => {
|
|
# Name => 'some name',
|
|
# Value => $Value,
|
|
#},
|
|
|
|
Attachment => [
|
|
{
|
|
Content => 'content' # base64 encoded
|
|
ContentType => 'some content type'
|
|
Filename => 'some fine name'
|
|
},
|
|
# ...
|
|
],
|
|
#or
|
|
#Attachment => {
|
|
# Content => 'content'
|
|
# ContentType => 'some content type'
|
|
# Filename => 'some fine name'
|
|
#},
|
|
},
|
|
);
|
|
|
|
$Result = {
|
|
Success => 1, # 0 or 1
|
|
ErrorMessage => '', # in case of error
|
|
Data => { # result data payload after Operation
|
|
TicketID => 123, # Ticket ID number in OTRS (help desk system)
|
|
TicketNumber => 2324454323322 # Ticket Number in OTRS (Help desk system)
|
|
ArticleID => 43, # Article ID number in OTRS (help desk system)
|
|
Error => { # should not return errors
|
|
ErrorCode => 'Ticket.Create.ErrorCode'
|
|
ErrorMessage => 'Error Description'
|
|
},
|
|
|
|
# If IncludeTicketData is enabled
|
|
Ticket => [
|
|
{
|
|
TicketNumber => '20101027000001',
|
|
Title => 'some title',
|
|
TicketID => 123,
|
|
State => 'some state',
|
|
StateID => 123,
|
|
StateType => 'some state type',
|
|
Priority => 'some priority',
|
|
PriorityID => 123,
|
|
Lock => 'lock',
|
|
LockID => 123,
|
|
Queue => 'some queue',
|
|
QueueID => 123,
|
|
CustomerID => 'customer_id_123',
|
|
CustomerUserID => 'customer_user_id_123',
|
|
Owner => 'some_owner_login',
|
|
OwnerID => 123,
|
|
Type => 'some ticket type',
|
|
TypeID => 123,
|
|
SLA => 'some sla',
|
|
SLAID => 123,
|
|
Service => 'some service',
|
|
ServiceID => 123,
|
|
Responsible => 'some_responsible_login',
|
|
ResponsibleID => 123,
|
|
Age => 3456,
|
|
Created => '2010-10-27 20:15:00'
|
|
CreateBy => 123,
|
|
Changed => '2010-10-27 20:15:15',
|
|
ChangeBy => 123,
|
|
ArchiveFlag => 'y',
|
|
|
|
DynamicField => [
|
|
{
|
|
Name => 'some name',
|
|
Value => 'some value',
|
|
},
|
|
],
|
|
|
|
# (time stamps of expected escalations)
|
|
EscalationResponseTime (unix time stamp of response time escalation)
|
|
EscalationUpdateTime (unix time stamp of update time escalation)
|
|
EscalationSolutionTime (unix time stamp of solution time escalation)
|
|
|
|
# (general escalation info of nearest escalation type)
|
|
EscalationDestinationIn (escalation in e. g. 1h 4m)
|
|
EscalationDestinationTime (date of escalation in unix time, e. g. 72193292)
|
|
EscalationDestinationDate (date of escalation, e. g. "2009-02-14 18:00:00")
|
|
EscalationTimeWorkingTime (seconds of working/service time till escalation, e. g. "1800")
|
|
EscalationTime (seconds total till escalation of nearest escalation time type - response, update or solution time, e. g. "3600")
|
|
|
|
# (detailed escalation info about first response, update and solution time)
|
|
FirstResponseTimeEscalation (if true, ticket is escalated)
|
|
FirstResponseTimeNotification (if true, notify - x% of escalation has reached)
|
|
FirstResponseTimeDestinationTime (date of escalation in unix time, e. g. 72193292)
|
|
FirstResponseTimeDestinationDate (date of escalation, e. g. "2009-02-14 18:00:00")
|
|
FirstResponseTimeWorkingTime (seconds of working/service time till escalation, e. g. "1800")
|
|
FirstResponseTime (seconds total till escalation, e. g. "3600")
|
|
|
|
UpdateTimeEscalation (if true, ticket is escalated)
|
|
UpdateTimeNotification (if true, notify - x% of escalation has reached)
|
|
UpdateTimeDestinationTime (date of escalation in unix time, e. g. 72193292)
|
|
UpdateTimeDestinationDate (date of escalation, e. g. "2009-02-14 18:00:00")
|
|
UpdateTimeWorkingTime (seconds of working/service time till escalation, e. g. "1800")
|
|
UpdateTime (seconds total till escalation, e. g. "3600")
|
|
|
|
SolutionTimeEscalation (if true, ticket is escalated)
|
|
SolutionTimeNotification (if true, notify - x% of escalation has reached)
|
|
SolutionTimeDestinationTime (date of escalation in unix time, e. g. 72193292)
|
|
SolutionTimeDestinationDate (date of escalation, e. g. "2009-02-14 18:00:00")
|
|
SolutionTimeWorkingTime (seconds of working/service time till escalation, e. g. "1800")
|
|
SolutionTime (seconds total till escalation, e. g. "3600")
|
|
|
|
Article => [
|
|
{
|
|
ArticleID
|
|
From
|
|
To
|
|
Cc
|
|
Subject
|
|
Body
|
|
ReplyTo
|
|
MessageID
|
|
InReplyTo
|
|
References
|
|
SenderType
|
|
SenderTypeID
|
|
CommunicationChannelID
|
|
IsVisibleForCustomer
|
|
ContentType
|
|
Charset
|
|
MimeType
|
|
IncomingTime
|
|
|
|
DynamicField => [
|
|
{
|
|
Name => 'some name',
|
|
Value => 'some value',
|
|
},
|
|
],
|
|
|
|
Attachment => [
|
|
{
|
|
Content => "xxxx", # actual attachment contents, base64 enconded
|
|
ContentAlternative => "",
|
|
ContentID => "",
|
|
ContentType => "application/pdf",
|
|
Filename => "StdAttachment-Test1.pdf",
|
|
Filesize => "4.6 KBytes",
|
|
FilesizeRaw => 4722,
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
],
|
|
},
|
|
};
|
|
|
|
=cut
|
|
|
|
sub Run {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Result = $Self->Init(
|
|
WebserviceID => $Self->{WebserviceID},
|
|
);
|
|
|
|
if ( !$Result->{Success} ) {
|
|
$Self->ReturnError(
|
|
ErrorCode => 'Webservice.InvalidConfiguration',
|
|
ErrorMessage => $Result->{ErrorMessage},
|
|
);
|
|
}
|
|
|
|
# check needed stuff
|
|
if (
|
|
!$Param{Data}->{UserLogin}
|
|
&& !$Param{Data}->{CustomerUserLogin}
|
|
&& !$Param{Data}->{SessionID}
|
|
)
|
|
{
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: UserLogin, CustomerUserLogin or SessionID is required!",
|
|
);
|
|
}
|
|
|
|
if ( $Param{Data}->{UserLogin} || $Param{Data}->{CustomerUserLogin} ) {
|
|
|
|
if ( !$Param{Data}->{Password} )
|
|
{
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Password or SessionID is required!",
|
|
);
|
|
}
|
|
}
|
|
|
|
# authenticate user
|
|
my ( $UserID, $UserType ) = $Self->Auth(
|
|
%Param,
|
|
);
|
|
|
|
if ( !$UserID ) {
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.AuthFail',
|
|
ErrorMessage => "TicketCreate: User could not be authenticated!",
|
|
);
|
|
}
|
|
|
|
my $PermissionUserID = $UserID;
|
|
if ( $UserType eq 'Customer' ) {
|
|
$UserID = $Kernel::OM->Get('Kernel::Config')->Get('CustomerPanelUserID');
|
|
}
|
|
|
|
# check needed hashes
|
|
for my $Needed (qw(Ticket Article)) {
|
|
if ( !IsHashRefWithData( $Param{Data}->{$Needed} ) ) {
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: $Needed parameter is missing or not valid!",
|
|
);
|
|
}
|
|
}
|
|
|
|
# check optional array/hashes
|
|
for my $Optional (qw(DynamicField Attachment)) {
|
|
if (
|
|
defined $Param{Data}->{$Optional}
|
|
&& !IsHashRefWithData( $Param{Data}->{$Optional} )
|
|
&& !IsArrayRefWithData( $Param{Data}->{$Optional} )
|
|
)
|
|
{
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: $Optional parameter is missing or not valid!",
|
|
);
|
|
}
|
|
}
|
|
|
|
# isolate ticket parameter
|
|
my $Ticket = $Param{Data}->{Ticket};
|
|
|
|
# remove leading and trailing spaces
|
|
for my $Attribute ( sort keys %{$Ticket} ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$Ticket->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$Ticket->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
if ( IsHashRefWithData( $Ticket->{PendingTime} ) ) {
|
|
for my $Attribute ( sort keys %{ $Ticket->{PendingTime} } ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$Ticket->{PendingTime}->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$Ticket->{PendingTime}->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
}
|
|
|
|
# check Ticket attribute values
|
|
my $TicketCheck = $Self->_CheckTicket( Ticket => $Ticket );
|
|
|
|
if ( !$TicketCheck->{Success} ) {
|
|
return $Self->ReturnError( %{$TicketCheck} );
|
|
}
|
|
|
|
# check create permissions
|
|
my $Permission = $Self->CheckCreatePermissions(
|
|
Ticket => $Ticket,
|
|
UserID => $PermissionUserID,
|
|
UserType => $UserType,
|
|
);
|
|
|
|
if ( !$Permission ) {
|
|
return $Self->ReturnError(
|
|
ErrorCode => 'TicketCreate.AccessDenied',
|
|
ErrorMessage => "TicketCreate: Can not create tickets in given Queue or QueueID!",
|
|
);
|
|
}
|
|
|
|
# isolate Article parameter
|
|
my $Article = $Param{Data}->{Article};
|
|
$Article->{UserType} = $UserType;
|
|
|
|
# remove leading and trailing spaces
|
|
for my $Attribute ( sort keys %{$Article} ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$Article->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$Article->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
if ( IsHashRefWithData( $Article->{OrigHeader} ) ) {
|
|
for my $Attribute ( sort keys %{ $Article->{OrigHeader} } ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$Article->{OrigHeader}->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$Article->{OrigHeader}->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
}
|
|
|
|
# Check attributes that can be set by sysconfig.
|
|
if ( !$Article->{AutoResponseType} ) {
|
|
$Article->{AutoResponseType} = $Self->{Config}->{AutoResponseType} || '';
|
|
}
|
|
|
|
# TODO: GenericInterface::Operation::TicketCreate###CommunicationChannel
|
|
if ( !$Article->{CommunicationChannelID} && !$Article->{CommunicationChannel} ) {
|
|
$Article->{CommunicationChannel} = 'Internal';
|
|
}
|
|
if ( !defined $Article->{IsVisibleForCustomer} ) {
|
|
$Article->{IsVisibleForCustomer} = $Self->{Config}->{IsVisibleForCustomer} // 1;
|
|
}
|
|
if ( !$Article->{SenderTypeID} && !$Article->{SenderType} ) {
|
|
$Article->{SenderType} = $UserType eq 'User' ? 'agent' : 'customer';
|
|
}
|
|
if ( !$Article->{HistoryType} ) {
|
|
$Article->{HistoryType} = $Self->{Config}->{HistoryType} || '';
|
|
}
|
|
if ( !$Article->{HistoryComment} ) {
|
|
$Article->{HistoryComment} = $Self->{Config}->{HistoryComment} || '';
|
|
}
|
|
|
|
# check Article attribute values
|
|
my $ArticleCheck = $Self->_CheckArticle( Article => $Article );
|
|
|
|
if ( !$ArticleCheck->{Success} ) {
|
|
if ( !$ArticleCheck->{ErrorCode} ) {
|
|
return {
|
|
Success => 0,
|
|
%{$ArticleCheck},
|
|
};
|
|
}
|
|
return $Self->ReturnError( %{$ArticleCheck} );
|
|
}
|
|
|
|
my $DynamicField;
|
|
my @DynamicFieldList;
|
|
|
|
if ( defined $Param{Data}->{DynamicField} ) {
|
|
|
|
# isolate DynamicField parameter
|
|
$DynamicField = $Param{Data}->{DynamicField};
|
|
|
|
# homogenate input to array
|
|
if ( ref $DynamicField eq 'HASH' ) {
|
|
push @DynamicFieldList, $DynamicField;
|
|
}
|
|
else {
|
|
@DynamicFieldList = @{$DynamicField};
|
|
}
|
|
|
|
# check DynamicField internal structure
|
|
for my $DynamicFieldItem (@DynamicFieldList) {
|
|
if ( !IsHashRefWithData($DynamicFieldItem) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->DynamicField parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# remove leading and trailing spaces
|
|
for my $Attribute ( sort keys %{$DynamicFieldItem} ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$DynamicFieldItem->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$DynamicFieldItem->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
|
|
# check DynamicField attribute values
|
|
my $DynamicFieldCheck = $Self->_CheckDynamicField( DynamicField => $DynamicFieldItem );
|
|
|
|
if ( !$DynamicFieldCheck->{Success} ) {
|
|
return $Self->ReturnError( %{$DynamicFieldCheck} );
|
|
}
|
|
}
|
|
}
|
|
|
|
my $Attachment;
|
|
my @AttachmentList;
|
|
|
|
if ( defined $Param{Data}->{Attachment} ) {
|
|
|
|
# isolate Attachment parameter
|
|
$Attachment = $Param{Data}->{Attachment};
|
|
|
|
# homogenate input to array
|
|
if ( ref $Attachment eq 'HASH' ) {
|
|
push @AttachmentList, $Attachment;
|
|
}
|
|
else {
|
|
@AttachmentList = @{$Attachment};
|
|
}
|
|
|
|
# check Attachment internal structure
|
|
for my $AttachmentItem (@AttachmentList) {
|
|
if ( !IsHashRefWithData($AttachmentItem) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->Attachment parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# remove leading and trailing spaces
|
|
for my $Attribute ( sort keys %{$AttachmentItem} ) {
|
|
if ( ref $Attribute ne 'HASH' && ref $Attribute ne 'ARRAY' ) {
|
|
|
|
#remove leading spaces
|
|
$AttachmentItem->{$Attribute} =~ s{\A\s+}{};
|
|
|
|
#remove trailing spaces
|
|
$AttachmentItem->{$Attribute} =~ s{\s+\z}{};
|
|
}
|
|
}
|
|
|
|
# check Attachment attribute values
|
|
my $AttachmentCheck = $Self->_CheckAttachment( Attachment => $AttachmentItem );
|
|
|
|
if ( !$AttachmentCheck->{Success} ) {
|
|
return $Self->ReturnError( %{$AttachmentCheck} );
|
|
}
|
|
}
|
|
}
|
|
|
|
return $Self->_TicketCreate(
|
|
Ticket => $Ticket,
|
|
Article => $Article,
|
|
DynamicFieldList => \@DynamicFieldList,
|
|
AttachmentList => \@AttachmentList,
|
|
UserID => $UserID,
|
|
);
|
|
}
|
|
|
|
=begin Internal:
|
|
|
|
=head2 _CheckTicket()
|
|
|
|
checks if the given ticket parameters are valid.
|
|
|
|
my $TicketCheck = $OperationObject->_CheckTicket(
|
|
Ticket => $Ticket, # all ticket parameters
|
|
);
|
|
|
|
returns:
|
|
|
|
$TicketCheck = {
|
|
Success => 1, # if everything is OK
|
|
}
|
|
|
|
$TicketCheck = {
|
|
ErrorCode => 'Function.Error', # if error
|
|
ErrorMessage => 'Error description',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub _CheckTicket {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Ticket = $Param{Ticket};
|
|
|
|
# check ticket internally
|
|
for my $Needed (qw(Title CustomerUser)) {
|
|
if ( !$Ticket->{$Needed} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->$Needed parameter is missing!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->CustomerUser
|
|
if ( !$Self->ValidateCustomer( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->CustomerUser parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Ticket->Queue
|
|
if ( !$Ticket->{QueueID} && !$Ticket->{Queue} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->QueueID or Ticket->Queue parameter is required!",
|
|
};
|
|
}
|
|
if ( !$Self->ValidateQueue( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->QueueID or Ticket->Queue parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Ticket->Lock
|
|
if ( $Ticket->{LockID} || $Ticket->{Lock} ) {
|
|
if ( !$Self->ValidateLock( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->LockID or Ticket->Lock parameter is"
|
|
. " invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->Type
|
|
# Ticket type could be required or not depending on sysconfig option
|
|
if (
|
|
!$Ticket->{TypeID}
|
|
&& !$Ticket->{Type}
|
|
&& $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Type')
|
|
)
|
|
{
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->TypeID or Ticket->Type parameter is required"
|
|
. " by sysconfig option!",
|
|
};
|
|
}
|
|
if ( $Ticket->{TypeID} || $Ticket->{Type} ) {
|
|
if ( !$Self->ValidateType( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->TypeID or Ticket->Type parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->Service
|
|
if ( $Ticket->{ServiceID} || $Ticket->{Service} ) {
|
|
if ( !$Self->ValidateService( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->ServiceID or Ticket->Service parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->SLA
|
|
if ( $Ticket->{SLAID} || $Ticket->{SLA} ) {
|
|
if ( !$Self->ValidateSLA( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->SLAID or Ticket->SLA parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->State
|
|
if ( !$Ticket->{StateID} && !$Ticket->{State} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->StateID or Ticket->State parameter is required!",
|
|
};
|
|
}
|
|
if ( !$Self->ValidateState( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->StateID or Ticket->State parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Ticket->Priority
|
|
if ( !$Ticket->{PriorityID} && !$Ticket->{Priority} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->PriorityID or Ticket->Priority parameter is"
|
|
. " required!",
|
|
};
|
|
}
|
|
if ( !$Self->ValidatePriority( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->PriorityID or Ticket->Priority parameter is"
|
|
. " invalid!",
|
|
};
|
|
}
|
|
|
|
# check Ticket->Owner
|
|
if ( $Ticket->{OwnerID} || $Ticket->{Owner} ) {
|
|
if ( !$Self->ValidateOwner( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage =>
|
|
"TicketCreate: Ticket->OwnerID or Ticket->Owner parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->Responsible
|
|
if ( $Ticket->{ResponsibleID} || $Ticket->{Responsible} ) {
|
|
if ( !$Self->ValidateResponsible( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->ResponsibleID or Ticket->Responsible"
|
|
. " parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Ticket->PendingTime
|
|
if ( $Ticket->{PendingTime} ) {
|
|
if ( !$Self->ValidatePendingTime( %{$Ticket} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Ticket->PendingTime parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# if everything is OK then return Success
|
|
return {
|
|
Success => 1,
|
|
};
|
|
}
|
|
|
|
=head2 _CheckArticle()
|
|
|
|
checks if the given article parameter is valid.
|
|
|
|
my $ArticleCheck = $OperationObject->_CheckArticle(
|
|
Article => $Article, # all article parameters
|
|
);
|
|
|
|
returns:
|
|
|
|
$ArticleCheck = {
|
|
Success => 1, # if everething is OK
|
|
}
|
|
|
|
$ArticleCheck = {
|
|
ErrorCode => 'Function.Error', # if error
|
|
ErrorMessage => 'Error description',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub _CheckArticle {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Article = $Param{Article};
|
|
|
|
# check ticket internally
|
|
for my $Needed (qw(Subject Body AutoResponseType)) {
|
|
if ( !$Article->{$Needed} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Article->$Needed parameter is missing!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->AutoResponseType
|
|
if ( !$Article->{AutoResponseType} ) {
|
|
|
|
# return internal server error
|
|
return {
|
|
ErrorMessage => "TicketCreate: Article->AutoResponseType parameter is required!"
|
|
};
|
|
}
|
|
|
|
if ( !$Self->ValidateAutoResponseType( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->AutoResponseType parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Article->CommunicationChannel
|
|
if ( !$Article->{CommunicationChannel} && !$Article->{CommunicationChannelID} ) {
|
|
|
|
# return internal server error
|
|
return {
|
|
ErrorMessage => "TicketCreate: Article->CommunicationChannelID or Article->CommunicationChannel parameter"
|
|
. " is required and Sysconfig CommunicationChannelID setting could not be read!"
|
|
};
|
|
}
|
|
if ( !$Self->ValidateArticleCommunicationChannel( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->CommunicationChannel or Article->CommunicationChannelID parameter"
|
|
. " is invalid or not supported!",
|
|
};
|
|
}
|
|
|
|
# check Article->SenderType
|
|
if ( !$Article->{SenderTypeID} && !$Article->{SenderType} ) {
|
|
|
|
# return internal server error
|
|
return {
|
|
ErrorMessage => "TicketCreate: Article->SenderTypeID or Article->SenderType parameter"
|
|
. " is required and Sysconfig SenderTypeID setting could not be read!"
|
|
};
|
|
}
|
|
if ( !$Self->ValidateSenderType( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->SenderTypeID or Ticket->SenderType parameter"
|
|
. " is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Article->From
|
|
if ( $Article->{From} ) {
|
|
if ( !$Self->ValidateFrom( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->From parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->ContentType vs Article->MimeType and Article->Charset
|
|
if ( !$Article->{ContentType} && !$Article->{MimeType} && !$Article->{Charset} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Article->ContentType or Ticket->MimeType and"
|
|
. " Article->Charset parameters are required!",
|
|
};
|
|
}
|
|
|
|
if ( $Article->{MimeType} && !$Article->{Charset} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Article->Charset is required!",
|
|
};
|
|
}
|
|
|
|
if ( $Article->{Charset} && !$Article->{MimeType} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Article->MimeType is required!",
|
|
};
|
|
}
|
|
|
|
# check Article->MimeType
|
|
if ( $Article->{MimeType} ) {
|
|
|
|
$Article->{MimeType} = lc $Article->{MimeType};
|
|
|
|
if ( !$Self->ValidateMimeType( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->MimeType is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->MimeType
|
|
if ( $Article->{Charset} ) {
|
|
|
|
$Article->{Charset} = lc $Article->{Charset};
|
|
|
|
if ( !$Self->ValidateCharset( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->Charset is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->ContentType
|
|
if ( $Article->{ContentType} ) {
|
|
|
|
$Article->{ContentType} = lc $Article->{ContentType};
|
|
|
|
# check Charset part
|
|
my $Charset = '';
|
|
if ( $Article->{ContentType} =~ /charset=/i ) {
|
|
$Charset = $Article->{ContentType};
|
|
$Charset =~ s/.+?charset=("|'|)(\w+)/$2/gi;
|
|
$Charset =~ s/"|'//g;
|
|
$Charset =~ s/(.+?);.*/$1/g;
|
|
}
|
|
|
|
if ( !$Self->ValidateCharset( Charset => $Charset ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->ContentType is invalid!",
|
|
};
|
|
}
|
|
|
|
# check MimeType part
|
|
my $MimeType = '';
|
|
if ( $Article->{ContentType} =~ /^(\w+\/\w+)/i ) {
|
|
$MimeType = $1;
|
|
$MimeType =~ s/"|'//g;
|
|
}
|
|
|
|
if ( !$Self->ValidateMimeType( MimeType => $MimeType ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->ContentType is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->HistoryType
|
|
if ( !$Article->{HistoryType} ) {
|
|
|
|
# return internal server error
|
|
return {
|
|
ErrorMessage => "TicketCreate: Article-> HistoryType is required and Sysconfig"
|
|
. " HistoryType setting could not be read!"
|
|
};
|
|
}
|
|
if ( !$Self->ValidateHistoryType( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->HistoryType parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Article->HistoryComment
|
|
if ( !$Article->{HistoryComment} ) {
|
|
|
|
# return internal server error
|
|
return {
|
|
ErrorMessage => "TicketCreate: Article->HistoryComment is required and Sysconfig"
|
|
. " HistoryComment setting could not be read!"
|
|
};
|
|
}
|
|
|
|
# get config object
|
|
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
|
|
|
# check Article->TimeUnit
|
|
# TimeUnit could be required or not depending on sysconfig option
|
|
if (
|
|
( !defined $Article->{TimeUnit} || !IsStringWithData( $Article->{TimeUnit} ) )
|
|
&& $ConfigObject->{'Ticket::Frontend::AccountTime'}
|
|
&& $ConfigObject->{'Ticket::Frontend::NeedAccountedTime'}
|
|
)
|
|
{
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Article->TimeUnit is required by sysconfig option!",
|
|
};
|
|
}
|
|
if ( $Article->{TimeUnit} ) {
|
|
if ( !$Self->ValidateTimeUnit( %{$Article} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->TimeUnit parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check Article->NoAgentNotify
|
|
if ( $Article->{NoAgentNotify} && $Article->{NoAgentNotify} ne '1' ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->NoAgent parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check Article array parameters
|
|
for my $Attribute (
|
|
qw( ForceNotificationToUserID ExcludeNotificationToUserID ExcludeMuteNotificationToUserID )
|
|
)
|
|
{
|
|
if ( defined $Article->{$Attribute} ) {
|
|
|
|
# check structure
|
|
if ( IsHashRefWithData( $Article->{$Attribute} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->$Attribute parameter is invalid!",
|
|
};
|
|
}
|
|
else {
|
|
if ( !IsArrayRefWithData( $Article->{$Attribute} ) ) {
|
|
$Article->{$Attribute} = [ $Article->{$Attribute} ];
|
|
}
|
|
for my $UserID ( @{ $Article->{$Attribute} } ) {
|
|
if ( !$Self->ValidateUserID( UserID => $UserID ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Article->$Attribute UserID=$UserID"
|
|
. " parameter is invalid!",
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# if everything is OK then return Success
|
|
return {
|
|
Success => 1,
|
|
};
|
|
}
|
|
|
|
=head2 _CheckDynamicField()
|
|
|
|
checks if the given dynamic field parameter is valid.
|
|
|
|
my $DynamicFieldCheck = $OperationObject->_CheckDynamicField(
|
|
DynamicField => $DynamicField, # all dynamic field parameters
|
|
);
|
|
|
|
returns:
|
|
|
|
$DynamicFieldCheck = {
|
|
Success => 1, # if everething is OK
|
|
}
|
|
|
|
$DynamicFieldCheck = {
|
|
ErrorCode => 'Function.Error', # if error
|
|
ErrorMessage => 'Error description',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub _CheckDynamicField {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $DynamicField = $Param{DynamicField};
|
|
|
|
# check DynamicField item internally
|
|
for my $Needed (qw(Name Value)) {
|
|
if (
|
|
!defined $DynamicField->{$Needed}
|
|
|| ( !IsString( $DynamicField->{$Needed} ) && ref $DynamicField->{$Needed} ne 'ARRAY' )
|
|
)
|
|
{
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: DynamicField->$Needed parameter is missing!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# check DynamicField->Name
|
|
if ( !$Self->ValidateDynamicFieldName( %{$DynamicField} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: DynamicField->Name parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# check DynamicField->Value
|
|
if ( !$Self->ValidateDynamicFieldValue( %{$DynamicField} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: DynamicField->Value parameter is invalid!",
|
|
};
|
|
}
|
|
|
|
# if everything is OK then return Success
|
|
return {
|
|
Success => 1,
|
|
};
|
|
}
|
|
|
|
=head2 _CheckAttachment()
|
|
|
|
checks if the given attachment parameter is valid.
|
|
|
|
my $AttachmentCheck = $OperationObject->_CheckAttachment(
|
|
Attachment => $Attachment, # all attachment parameters
|
|
);
|
|
|
|
returns:
|
|
|
|
$AttachmentCheck = {
|
|
Success => 1, # if everething is OK
|
|
}
|
|
|
|
$AttachmentCheck = {
|
|
ErrorCode => 'Function.Error', # if error
|
|
ErrorMessage => 'Error description',
|
|
}
|
|
|
|
=cut
|
|
|
|
sub _CheckAttachment {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Attachment = $Param{Attachment};
|
|
|
|
# check attachment item internally
|
|
for my $Needed (qw(Content ContentType)) {
|
|
if ( !$Attachment->{$Needed} ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Attachment->$Needed parameter is missing!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# Check Filename separately because it can be '0'. See bug#14761.
|
|
if ( !IsStringWithData( $Attachment->{Filename} ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.MissingParameter',
|
|
ErrorMessage => "TicketCreate: Attachment->Filename parameter is missing!",
|
|
};
|
|
}
|
|
|
|
# check Article->ContentType
|
|
if ( $Attachment->{ContentType} ) {
|
|
|
|
$Attachment->{ContentType} = lc $Attachment->{ContentType};
|
|
|
|
# check Charset part
|
|
my $Charset = '';
|
|
if ( $Attachment->{ContentType} =~ /charset=/i ) {
|
|
$Charset = $Attachment->{ContentType};
|
|
$Charset =~ s/.+?charset=("|'|)(\w+)/$2/gi;
|
|
$Charset =~ s/"|'//g;
|
|
$Charset =~ s/(.+?);.*/$1/g;
|
|
}
|
|
|
|
if ( $Charset && !$Self->ValidateCharset( Charset => $Charset ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Attachment->ContentType is invalid!",
|
|
};
|
|
}
|
|
|
|
# check MimeType part
|
|
my $MimeType = '';
|
|
if ( $Attachment->{ContentType} =~ /^(\w+\/\w+)/i ) {
|
|
$MimeType = $1;
|
|
$MimeType =~ s/"|'//g;
|
|
}
|
|
|
|
if ( !$Self->ValidateMimeType( MimeType => $MimeType ) ) {
|
|
return {
|
|
ErrorCode => 'TicketCreate.InvalidParameter',
|
|
ErrorMessage => "TicketCreate: Attachment->ContentType is invalid!",
|
|
};
|
|
}
|
|
}
|
|
|
|
# if everything is OK then return Success
|
|
return {
|
|
Success => 1,
|
|
};
|
|
}
|
|
|
|
=head2 _TicketCreate()
|
|
|
|
creates a ticket with its article and sets dynamic fields and attachments if specified.
|
|
|
|
my $Response = $OperationObject->_TicketCreate(
|
|
Ticket => $Ticket, # all ticket parameters
|
|
Article => $Article, # all attachment parameters
|
|
DynamicField => $DynamicField, # all dynamic field parameters
|
|
Attachment => $Attachment, # all attachment parameters
|
|
UserID => 123,
|
|
);
|
|
|
|
returns:
|
|
|
|
$Response = {
|
|
Success => 1, # if everything was OK
|
|
Data => {
|
|
TicketID => 123,
|
|
TicketNumber => 'TN3422332',
|
|
ArticleID => 123,
|
|
}
|
|
}
|
|
|
|
$Response = {
|
|
Success => 0, # if unexpected error
|
|
ErrorMessage => "$Param{ErrorCode}: $Param{ErrorMessage}",
|
|
}
|
|
|
|
=cut
|
|
|
|
sub _TicketCreate {
|
|
my ( $Self, %Param ) = @_;
|
|
|
|
my $Ticket = $Param{Ticket};
|
|
my $Article = $Param{Article};
|
|
my $DynamicFieldList = $Param{DynamicFieldList};
|
|
my $AttachmentList = $Param{AttachmentList};
|
|
|
|
# get customer information
|
|
# with information will be used to create the ticket if customer is not defined in the
|
|
# database, customer ticket information need to be empty strings
|
|
my %CustomerUserData = $Kernel::OM->Get('Kernel::System::CustomerUser')->CustomerUserDataGet(
|
|
User => $Ticket->{CustomerUser},
|
|
);
|
|
|
|
my $CustomerID = $CustomerUserData{UserCustomerID} || '';
|
|
|
|
# use user defined CustomerID if defined
|
|
if ( defined $Ticket->{CustomerID} && $Ticket->{CustomerID} ne '' ) {
|
|
$CustomerID = $Ticket->{CustomerID};
|
|
}
|
|
|
|
# get database object
|
|
my $UserObject = $Kernel::OM->Get('Kernel::System::User');
|
|
|
|
my $OwnerID;
|
|
if ( $Ticket->{Owner} && !$Ticket->{OwnerID} ) {
|
|
my %OwnerData = $UserObject->GetUserData(
|
|
User => $Ticket->{Owner},
|
|
);
|
|
$OwnerID = $OwnerData{UserID};
|
|
}
|
|
elsif ( defined $Ticket->{OwnerID} ) {
|
|
$OwnerID = $Ticket->{OwnerID};
|
|
}
|
|
|
|
my $ResponsibleID;
|
|
if ( $Ticket->{Responsible} && !$Ticket->{ResponsibleID} ) {
|
|
my %ResponsibleData = $UserObject->GetUserData(
|
|
User => $Ticket->{Responsible},
|
|
);
|
|
$ResponsibleID = $ResponsibleData{UserID};
|
|
}
|
|
elsif ( defined $Ticket->{ResponsibleID} ) {
|
|
$ResponsibleID = $Ticket->{ResponsibleID};
|
|
}
|
|
|
|
# get ticket object
|
|
my $TicketObject = $Kernel::OM->Get('Kernel::System::Ticket');
|
|
|
|
# create new ticket
|
|
my $TicketID = $TicketObject->TicketCreate(
|
|
Title => $Ticket->{Title},
|
|
QueueID => $Ticket->{QueueID} || '',
|
|
Queue => $Ticket->{Queue} || '',
|
|
Lock => 'unlock',
|
|
TypeID => $Ticket->{TypeID} || '',
|
|
Type => $Ticket->{Type} || '',
|
|
ServiceID => $Ticket->{ServiceID} || '',
|
|
Service => $Ticket->{Service} || '',
|
|
SLAID => $Ticket->{SLAID} || '',
|
|
SLA => $Ticket->{SLA} || '',
|
|
StateID => $Ticket->{StateID} || '',
|
|
State => $Ticket->{State} || '',
|
|
PriorityID => $Ticket->{PriorityID} || '',
|
|
Priority => $Ticket->{Priority} || '',
|
|
OwnerID => 1,
|
|
CustomerNo => $CustomerID,
|
|
CustomerUser => $CustomerUserData{UserLogin} || '',
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
if ( !$TicketID ) {
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => 'Ticket could not be created, please contact the system administrator',
|
|
};
|
|
}
|
|
|
|
# set lock if specified
|
|
if ( $Ticket->{Lock} || $Ticket->{LockID} ) {
|
|
$TicketObject->TicketLockSet(
|
|
TicketID => $TicketID,
|
|
LockID => $Ticket->{LockID} || '',
|
|
Lock => $Ticket->{Lock} || '',
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
# get State Data
|
|
my %StateData;
|
|
my $StateID;
|
|
|
|
# get state object
|
|
my $StateObject = $Kernel::OM->Get('Kernel::System::State');
|
|
|
|
if ( $Ticket->{StateID} ) {
|
|
$StateID = $Ticket->{StateID};
|
|
}
|
|
else {
|
|
$StateID = $StateObject->StateLookup(
|
|
State => $Ticket->{State},
|
|
);
|
|
}
|
|
|
|
%StateData = $StateObject->StateGet(
|
|
ID => $StateID,
|
|
);
|
|
|
|
# force unlock if state type is close
|
|
if ( $StateData{TypeName} =~ /^close/i ) {
|
|
|
|
# set lock
|
|
$TicketObject->TicketLockSet(
|
|
TicketID => $TicketID,
|
|
Lock => 'unlock',
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
# set pending time
|
|
elsif ( $StateData{TypeName} =~ /^pending/i ) {
|
|
|
|
# set pending time
|
|
if ( defined $Ticket->{PendingTime} ) {
|
|
$TicketObject->TicketPendingTimeSet(
|
|
UserID => $Param{UserID},
|
|
TicketID => $TicketID,
|
|
%{ $Ticket->{PendingTime} },
|
|
);
|
|
}
|
|
}
|
|
|
|
# set dynamic fields (only for object type 'ticket')
|
|
if ( IsArrayRefWithData($DynamicFieldList) ) {
|
|
|
|
DYNAMICFIELD:
|
|
for my $DynamicField ( @{$DynamicFieldList} ) {
|
|
next DYNAMICFIELD if !$Self->ValidateDynamicFieldObjectType( %{$DynamicField} );
|
|
|
|
my $Result = $Self->SetDynamicFieldValue(
|
|
%{$DynamicField},
|
|
TicketID => $TicketID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
if ( !$Result->{Success} ) {
|
|
my $ErrorMessage =
|
|
$Result->{ErrorMessage} || "Dynamic Field $DynamicField->{Name} could not be"
|
|
. " set, please contact the system administrator";
|
|
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => $ErrorMessage,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !defined $Article->{NoAgentNotify} ) {
|
|
|
|
# check if new owner is given (then send no agent notify)
|
|
$Article->{NoAgentNotify} = 0;
|
|
if ($OwnerID) {
|
|
$Article->{NoAgentNotify} = 1;
|
|
}
|
|
}
|
|
|
|
# set Article From
|
|
my $From;
|
|
if ( $Article->{From} ) {
|
|
$From = $Article->{From};
|
|
}
|
|
|
|
# use data from customer user (if customer user is in database)
|
|
elsif ( IsHashRefWithData( \%CustomerUserData ) ) {
|
|
$From = '"' . $CustomerUserData{UserFullname} . '"'
|
|
. ' <' . $CustomerUserData{UserEmail} . '>';
|
|
}
|
|
|
|
# otherwise use customer user as sent from the request (it should be an email)
|
|
else {
|
|
$From = $Ticket->{CustomerUser};
|
|
}
|
|
|
|
# set Article To
|
|
my $To;
|
|
if ( $Ticket->{Queue} ) {
|
|
$To = $Ticket->{Queue};
|
|
}
|
|
else {
|
|
$To = $Kernel::OM->Get('Kernel::System::Queue')->QueueLookup(
|
|
QueueID => $Ticket->{QueueID},
|
|
);
|
|
}
|
|
|
|
if ( !$Article->{CommunicationChannel} ) {
|
|
|
|
my %CommunicationChannel = $Kernel::OM->Get('Kernel::System::CommunicationChannel')->ChannelGet(
|
|
ChannelID => $Article->{CommunicationChannelID},
|
|
);
|
|
$Article->{CommunicationChannel} = $CommunicationChannel{ChannelName};
|
|
}
|
|
|
|
my $ArticleBackendObject = $Kernel::OM->Get('Kernel::System::Ticket::Article')->BackendForChannel(
|
|
ChannelName => $Article->{CommunicationChannel},
|
|
);
|
|
|
|
my $PlainBody = $Article->{Body};
|
|
|
|
# Convert article body to plain text, if HTML content was supplied. This is necessary since auto response code
|
|
# expects plain text content. Please see bug#13397 for more information.
|
|
if ( $Article->{ContentType} =~ /text\/html/i || $Article->{MimeType} =~ /text\/html/i ) {
|
|
$PlainBody = $Kernel::OM->Get('Kernel::System::HTMLUtils')->ToAscii(
|
|
String => $Article->{Body},
|
|
);
|
|
}
|
|
|
|
# Create article.
|
|
my $ArticleID = $ArticleBackendObject->ArticleCreate(
|
|
NoAgentNotify => $Article->{NoAgentNotify} || 0,
|
|
TicketID => $TicketID,
|
|
SenderTypeID => $Article->{SenderTypeID} || '',
|
|
SenderType => $Article->{SenderType} || '',
|
|
IsVisibleForCustomer => $Article->{IsVisibleForCustomer},
|
|
From => $From,
|
|
To => $To,
|
|
Subject => $Article->{Subject},
|
|
Body => $Article->{Body},
|
|
MimeType => $Article->{MimeType} || '',
|
|
Charset => $Article->{Charset} || '',
|
|
ContentType => $Article->{ContentType} || '',
|
|
UserID => $Param{UserID},
|
|
HistoryType => $Article->{HistoryType},
|
|
HistoryComment => $Article->{HistoryComment} || '%%',
|
|
AutoResponseType => $Article->{AutoResponseType},
|
|
OrigHeader => {
|
|
From => $From,
|
|
To => $To,
|
|
Subject => $Article->{Subject},
|
|
Body => $PlainBody,
|
|
},
|
|
);
|
|
|
|
if ( !$ArticleID ) {
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => 'Article could not be created, please contact the system administrator',
|
|
};
|
|
}
|
|
|
|
# set owner (if owner or owner id is given)
|
|
if ($OwnerID) {
|
|
$TicketObject->TicketOwnerSet(
|
|
TicketID => $TicketID,
|
|
NewUserID => $OwnerID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
# set lock if no lock was defined
|
|
if ( !$Ticket->{Lock} && !$Ticket->{LockID} ) {
|
|
$TicketObject->TicketLockSet(
|
|
TicketID => $TicketID,
|
|
Lock => 'lock',
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
}
|
|
|
|
# else set owner to current agent but do not lock it
|
|
else {
|
|
$TicketObject->TicketOwnerSet(
|
|
TicketID => $TicketID,
|
|
NewUserID => $Param{UserID},
|
|
SendNoNotification => 1,
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
# set responsible
|
|
if ($ResponsibleID) {
|
|
$TicketObject->TicketResponsibleSet(
|
|
TicketID => $TicketID,
|
|
NewUserID => $ResponsibleID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
# time accounting
|
|
if ( $Article->{TimeUnit} ) {
|
|
$TicketObject->TicketAccountTime(
|
|
TicketID => $TicketID,
|
|
ArticleID => $ArticleID,
|
|
TimeUnit => $Article->{TimeUnit},
|
|
UserID => $Param{UserID},
|
|
);
|
|
}
|
|
|
|
# set dynamic fields (only for object type 'article')
|
|
if ( IsArrayRefWithData($DynamicFieldList) ) {
|
|
|
|
DYNAMICFIELD:
|
|
for my $DynamicField ( @{$DynamicFieldList} ) {
|
|
|
|
my $IsArticleDynamicField = $Self->ValidateDynamicFieldObjectType(
|
|
%{$DynamicField},
|
|
Article => 1,
|
|
);
|
|
next DYNAMICFIELD if !$IsArticleDynamicField;
|
|
|
|
my $Result = $Self->SetDynamicFieldValue(
|
|
%{$DynamicField},
|
|
TicketID => $TicketID,
|
|
ArticleID => $ArticleID,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
if ( !$Result->{Success} ) {
|
|
my $ErrorMessage =
|
|
$Result->{ErrorMessage} || "Dynamic Field $DynamicField->{Name} could not be"
|
|
. " set, please contact the system administrator";
|
|
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => $ErrorMessage,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
# set attachments
|
|
if ( IsArrayRefWithData($AttachmentList) ) {
|
|
|
|
for my $Attachment ( @{$AttachmentList} ) {
|
|
my $Result = $Self->CreateAttachment(
|
|
TicketID => $TicketID,
|
|
Attachment => $Attachment,
|
|
ArticleID => $ArticleID,
|
|
UserID => $Param{UserID}
|
|
);
|
|
|
|
if ( !$Result->{Success} ) {
|
|
my $ErrorMessage =
|
|
$Result->{ErrorMessage} || "Attachment could not be created, please contact"
|
|
. " the system administrator";
|
|
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => $ErrorMessage,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
# get ticket data
|
|
my %TicketData = $TicketObject->TicketGet(
|
|
TicketID => $TicketID,
|
|
DynamicFields => 1,
|
|
UserID => $Param{UserID},
|
|
);
|
|
|
|
if ( !IsHashRefWithData( \%TicketData ) ) {
|
|
return {
|
|
Success => 0,
|
|
ErrorMessage => 'Could not get new ticket information, please contact the system'
|
|
. ' administrator',
|
|
};
|
|
}
|
|
|
|
# get web service configuration
|
|
my $Webservice = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice')->WebserviceGet(
|
|
ID => $Self->{WebserviceID},
|
|
);
|
|
|
|
my $IncludeTicketData;
|
|
|
|
# Get operation config, if operation name was supplied.
|
|
if ( $Self->{Operation} ) {
|
|
my $OperationConfig = $Webservice->{Config}->{Provider}->{Operation}->{ $Self->{Operation} };
|
|
$IncludeTicketData = $OperationConfig->{IncludeTicketData};
|
|
}
|
|
|
|
if ( !$IncludeTicketData ) {
|
|
return {
|
|
Success => 1,
|
|
Data => {
|
|
TicketID => $TicketID,
|
|
TicketNumber => $TicketData{TicketNumber},
|
|
ArticleID => $ArticleID,
|
|
},
|
|
};
|
|
}
|
|
|
|
# extract all dynamic fields from main ticket hash.
|
|
my %TicketDynamicFields;
|
|
TICKETATTRIBUTE:
|
|
for my $TicketAttribute ( sort keys %TicketData ) {
|
|
if ( $TicketAttribute =~ m{\A DynamicField_(.*) \z}msx ) {
|
|
$TicketDynamicFields{$1} = {
|
|
Name => $1,
|
|
Value => $TicketData{$TicketAttribute},
|
|
};
|
|
delete $TicketData{$TicketAttribute};
|
|
}
|
|
}
|
|
|
|
# add dynamic fields as array into 'DynamicField' hash key if any
|
|
if (%TicketDynamicFields) {
|
|
$TicketData{DynamicField} = [ sort { $a->{Name} cmp $b->{Name} } values %TicketDynamicFields ];
|
|
}
|
|
|
|
# prepare TicketData and get Article
|
|
my %ArticleData = $ArticleBackendObject->ArticleGet(
|
|
TicketID => $TicketID,
|
|
ArticleID => $ArticleID,
|
|
DynamicFields => 1,
|
|
);
|
|
|
|
# prepare Article DynamicFields
|
|
my @ArticleDynamicFields;
|
|
|
|
# remove all dynamic fields form main ticket hash and set them into an array.
|
|
ARTICLEATTRIBUTE:
|
|
for my $ArticleAttribute ( sort keys %ArticleData ) {
|
|
if ( $ArticleAttribute =~ m{\A DynamicField_(.*) \z}msx ) {
|
|
if ( !exists $TicketDynamicFields{$1} ) {
|
|
push @ArticleDynamicFields, {
|
|
Name => $1,
|
|
Value => $ArticleData{$ArticleAttribute},
|
|
};
|
|
}
|
|
|
|
delete $ArticleData{$ArticleAttribute};
|
|
}
|
|
}
|
|
|
|
# add dynamic fields array into 'DynamicField' hash key if any
|
|
if (@ArticleDynamicFields) {
|
|
$ArticleData{DynamicField} = \@ArticleDynamicFields;
|
|
}
|
|
|
|
# add attachment if the request includes attachments
|
|
if ( IsArrayRefWithData($AttachmentList) ) {
|
|
my %AttachmentIndex = $ArticleBackendObject->ArticleAttachmentIndex(
|
|
ArticleID => $ArticleID,
|
|
);
|
|
|
|
my @Attachments;
|
|
$Kernel::OM->Get('Kernel::System::Main')->Require('MIME::Base64');
|
|
ATTACHMENT:
|
|
for my $FileID ( sort keys %AttachmentIndex ) {
|
|
next ATTACHMENT if !$FileID;
|
|
my %Attachment = $ArticleBackendObject->ArticleAttachment(
|
|
ArticleID => $ArticleID,
|
|
FileID => $FileID,
|
|
);
|
|
|
|
next ATTACHMENT if !IsHashRefWithData( \%Attachment );
|
|
|
|
# convert content to base64, but prevent 76 chars brake, see bug#14500.
|
|
$Attachment{Content} = MIME::Base64::encode_base64( $Attachment{Content}, '' );
|
|
push @Attachments, {%Attachment};
|
|
}
|
|
|
|
# set Attachments data
|
|
if (@Attachments) {
|
|
$ArticleData{Attachment} = \@Attachments;
|
|
}
|
|
}
|
|
|
|
$TicketData{Article} = \%ArticleData;
|
|
|
|
return {
|
|
Success => 1,
|
|
Data => {
|
|
TicketID => $TicketID,
|
|
TicketNumber => $TicketData{TicketNumber},
|
|
ArticleID => $ArticleID,
|
|
Ticket => \%TicketData,
|
|
},
|
|
};
|
|
}
|
|
|
|
1;
|
|
|
|
=end Internal:
|
|
|
|
=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
|