.\" Automatically generated by Pod::Man 4.07 (Pod::Simple 3.32) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" ======================================================================== .\" .IX Title "RT::Extension::SLA 3pm" .TH RT::Extension::SLA 3pm "2016-12-23" "perl v5.24.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" RT::Extension::SLA \- Service Level Agreements for RT .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\s-1RT\s0 extension to implement automated due dates using service levels. .SH "INSTALLATION" .IX Header "INSTALLATION" .ie n .IP """perl Makefile.PL""" 4 .el .IP "\f(CWperl Makefile.PL\fR" 4 .IX Item "perl Makefile.PL" .PD 0 .ie n .IP """make""" 4 .el .IP "\f(CWmake\fR" 4 .IX Item "make" .ie n .IP """make install""" 4 .el .IP "\f(CWmake install\fR" 4 .IX Item "make install" .PD May need root permissions .ie n .IP """make initdb""" 4 .el .IP "\f(CWmake initdb\fR" 4 .IX Item "make initdb" Only run this the first time you install this module. .Sp If you run this twice, you may end up with duplicate data in your database. .Sp If you are upgrading this module, check for upgrading instructions in case changes need to be made to your database. .IP "Edit your \fI/opt/rt4/etc/RT_SiteConfig.pm\fR" 4 .IX Item "Edit your /opt/rt4/etc/RT_SiteConfig.pm" If you are using \s-1RT 4.2\s0 or greater, add this line: .Sp .Vb 1 \& Plugin(\*(AqRT::Extension::SLA\*(Aq); .Ve .Sp For \s-1RT 3.8\s0 and 4.0, add this line: .Sp .Vb 1 \& Set(@Plugins, qw(RT::Extension::SLA)); .Ve .Sp or add \f(CW\*(C`RT::Extension::SLA\*(C'\fR to your existing \f(CW@Plugins\fR line. .IP "Restart your webserver" 4 .IX Item "Restart your webserver" .SH "UPGRADING" .IX Header "UPGRADING" .SS "From versions prior to 0.06" .IX Subsection "From versions prior to 0.06" You need to run an upgrade step on your \s-1RT\s0 database so this extension continues to work. Run the following from inside the source of this extension: .PP .Vb 1 \& /opt/rt4/sbin/rt\-setup\-database \-\-action insert \-\-datafile etc/upgrade/0.06/content .Ve .PP It will prompt you for your \s-1DBA\s0 password and should complete without error. .SH "CONFIGURATION" .IX Header "CONFIGURATION" Service level agreements of tickets is controlled by an \s-1SLA\s0 custom field (\s-1CF\s0). This field is created during \f(CW\*(C`make initdb\*(C'\fR step (above) and applied globally. This \s-1CF MUST\s0 be of \f(CW\*(C`select one value\*(C'\fR type. Values of the \s-1CF\s0 define the service levels. .PP It's possible to define different set of levels for different queues. You can create several CFs with the same name and different set of values. But if you move tickets between queues a lot then it's going to be a problem and it's preferred to use \fB\s-1ONE\s0\fR \s-1SLA\s0 custom field. .PP There is no WebUI in the current version. Almost everything is controlled in the \s-1RT\s0's config using option \f(CW%RT::ServiceAgreements\fR and \f(CW%RT::ServiceBusinessHours\fR. For example: .PP .Vb 10 \& %RT::ServiceAgreements = ( \& Default => \*(Aq4h\*(Aq, \& QueueDefault => { \& \*(AqIncident\*(Aq => \*(Aq2h\*(Aq, \& }, \& Levels => { \& \*(Aq2h\*(Aq => { Resolve => { RealMinutes => 60*2 } }, \& \*(Aq4h\*(Aq => { Resolve => { RealMinutes => 60*4 } }, \& }, \& ); .Ve .PP In this example \fIIncident\fR is the name of the queue, and \fI2h\fR is the name of the \s-1SLA\s0 which will be applied to this queue by default. .PP Each service level can be described using several options: Starts, Resolve, Response, KeepInLoop, OutOfHours and ServiceBusinessHours. .SS "Starts (interval, first business minute)" .IX Subsection "Starts (interval, first business minute)" By default when a ticket is created Starts date is set to first business minute after time of creation. In other words if a ticket is created during business hours then Starts will be equal to Created time, otherwise Starts will be beginning of the next business day. .PP However, if you provide 24/7 support then you most probably would be interested in Starts to be always equal to Created time. .PP Starts option can be used to adjust behaviour. Format of the option is the same as format for deadlines which described later in details. RealMinutes, BusinessMinutes options and OutOfHours modifiers can be used here like for any other deadline. For example: .PP .Vb 4 \& \*(Aqstandard\*(Aq => { \& # give people 15 minutes \& Starts => { BusinessMinutes => 15 }, \& }, .Ve .PP You can still use old option StartImmediately to set Starts date equal to Created date. .PP Example: .PP .Vb 4 \& \*(Aq24/7\*(Aq => { \& StartImmediately => 1, \& Response => { RealMinutes => 30 }, \& }, .Ve .PP But it's the same as: .PP .Vb 4 \& \*(Aq24/7\*(Aq => { \& Starts => { RealMinutes => 0 }, \& Response => { RealMinutes => 30 }, \& }, .Ve .SS "Resolve and Response (interval, no defaults)" .IX Subsection "Resolve and Response (interval, no defaults)" These two options define deadlines for resolve of a ticket and reply to customer(requestors) questions accordingly. .PP You can define them using real time, business or both. Read more about the latter below. .PP The Due date field is used to store calculated deadlines. .PP \fIResolve\fR .IX Subsection "Resolve" .PP Defines deadline when a ticket should be resolved. This option is quite simple and straightforward when used without \*(L"Response\*(R". .PP Example: .PP .Vb 5 \& # 8 business hours \& \*(Aqsimple\*(Aq => { Resolve => 60*8 }, \& ... \& # one real week \& \*(Aqhard\*(Aq => { Resolve => { RealMinutes => 60*24*7 } }, .Ve .PP \fIResponse\fR .IX Subsection "Response" .PP In many companies providing support service(s) resolve time of a ticket is less important than time of response to requestors from staff members. .PP You can use Response option to define such deadlines. The Due date is set when a ticket is created, unset when a worker replies, and re-set when the requestor replies again \*(-- until the ticket is closed, when the ticket's Due date is unset. .PP \&\fB\s-1NOTE\s0\fR that this behaviour changes when Resolve and Response options are combined; see \*(L"Using both Resolve and Response in the same level\*(R". .PP Note that by default, only the requestors on the ticket are considered \&\*(L"outside actors\*(R" and thus require a Response due date; all other email addresses are treated as workers of the ticket, and thus count as meeting the \s-1SLA. \s0 If you'd like to invert this logic, so that the Owner and AdminCcs are the only worker email addresses, and all others are external, see the \*(L"AssumeOutsideActor\*(R" configuration. .PP The owner is never treated as an outside actor; if they are also the requestor of the ticket, it will have no \s-1SLA.\s0 .PP If an outside actor replies multiple times, their later replies are ignored; the deadline is awlways calculated from the oldest correspondence from the outside actor. .PP \fIUsing both Resolve and Response in the same level\fR .IX Subsection "Using both Resolve and Response in the same level" .PP Resolve and Response can be combined. In such case due date is set according to the earliest of two deadlines and never is dropped to \&'not set'. .PP If a ticket met its Resolve deadline then due date stops \*(L"flipping\*(R", is freezed and the ticket becomes overdue. Before that moment when an inside actor replies to a ticket, due date is changed to Resolve deadline instead of 'Not Set', as well this happens when a ticket is closed. So all the time due date is defined. .PP Example: .PP .Vb 4 \& \*(Aqstandard delivery\*(Aq => { \& Response => { RealMinutes => 60*1 }, # one hour \& Resolve => { RealMinutes => 60*24 }, # 24 real hours \& }, .Ve .PP A client orders goods and due date of the order is set to the next one hour, you have this hour to process the order and write a reply. As soon as goods are delivered you resolve tickets and usually meet Resolve deadline, but if you don't resolve or user replies then most probably there are problems with delivery of the goods. And if after a week you keep replying to the client and always meeting one hour response deadline that doesn't mean the ticket is not over due. Due date was frozen 24 hours after creation of the order. .PP \fIUsing business and real time in one option\fR .IX Subsection "Using business and real time in one option" .PP It's quite rare situation when people need it, but we've decided that business is applied first and then real time when deadline described using both types of time. For example: .PP .Vb 7 \& \*(Aqdelivery\*(Aq => { \& Resolve => { BusinessMinutes => 0, RealMinutes => 60*8 }, \& }, \& \*(Aqfast delivery\*(Aq { \& StartImmediately => 1, \& Resolve => { RealMinutes => 60*8 }, \& }, .Ve .PP For delivery requests which come into the system during business hours these levels define the same deadlines, otherwise the first level set deadline to 8 real hours starting from the next business day, when tickets with the second level should be resolved in the next 8 hours after creation. .SS "Keep in loop (interval, no defaults)" .IX Subsection "Keep in loop (interval, no defaults)" If response deadline is used then Due date is changed to repsonse deadline or to \*(L"Not Set\*(R" when staff replies to a ticket. In some cases you want to keep requestors in loop and keed them up to date every few hours. KeepInLoop option can be used to achieve this. .PP .Vb 5 \& \*(Aqincident\*(Aq => { \& Response => { RealMinutes => 60*1 }, # one hour \& KeepInLoop => { RealMinutes => 60*2 }, # two hours \& Resolve => { RealMinutes => 60*24 }, # 24 real hours \& }, .Ve .PP In the above example Due is set to one hour after creation, reply of a inside actor moves Due date two hours forward, outside actors' replies move Due date to one hour and resolve deadine is 24 hours. .SS "Modifying Agreements" .IX Subsection "Modifying Agreements" \fIOutOfHours (struct, no default)\fR .IX Subsection "OutOfHours (struct, no default)" .PP Out of hours modifier. Adds more real or business minutes to resolve and/or reply options if event happens out of business hours, read also below. .PP Example: .PP .Vb 4 \& \*(Aqlevel x\*(Aq => { \& OutOfHours => { Resolve => { RealMinutes => +60*24 } }, \& Resolve => { RealMinutes => 60*24 }, \& }, .Ve .PP If a request comes into the system during night then supporters have two hours, otherwise only one. .PP .Vb 4 \& \*(Aqlevel x\*(Aq => { \& OutOfHours => { Response => { BusinessMinutes => +60*2 } }, \& Resolve => { BusinessMinutes => 60 }, \& }, .Ve .PP Supporters have two additional hours in the morning to deal with bunch of requests that came into the system during the last night. .PP \fIIgnoreOnStatuses (array, no default)\fR .IX Subsection "IgnoreOnStatuses (array, no default)" .PP Allows you to ignore a deadline when ticket has certain status. Example: .PP .Vb 3 \& \*(Aqlevel x\*(Aq => { \& KeepInLoop => { BusinessMinutes => 60, IgnoreOnStatuses => [\*(Aqstalled\*(Aq] }, \& }, .Ve .PP In above example KeepInLoop deadline is ignored if ticket is stalled. .PP \&\fB\s-1NOTE\s0\fR: When a ticket goes from an ignored status to a normal status, the new Due date is calculated from the last action (reply, \s-1SLA\s0 change, etc) which fits the \s-1SLA\s0 type (Response, Starts, KeepInLoop, etc). This means if a ticket in the above example flips from stalled to open without a reply, the ticket will probably be overdue. In most cases this shouldn't be a problem since moving out of stalled-like statuses is often the result of \s-1RT\s0's auto-open on reply scrip, therefore ensuring there's a new reply to calculate Due from. The overall effect is that ignored statuses don't let the Due date drift arbitrarily, which could wreak havoc on your \s-1SLA\s0 performance. .SS "Configuring business hours" .IX Subsection "Configuring business hours" In the config you can set one or more work schedules. Use the following format: .PP .Vb 11 \& %RT::ServiceBusinessHours = ( \& \*(AqDefault\*(Aq => { \& ... description ... \& }, \& \*(AqSupport\*(Aq => { \& ... description ... \& }, \& \*(AqSales\*(Aq => { \& ... description ... \& }, \& ); .Ve .PP Read more about how to describe a schedule in Business::Hours. .PP \fIDefining different business hours for service levels\fR .IX Subsection "Defining different business hours for service levels" .PP Each level supports BusinessHours option to specify your own business hours. .PP .Vb 4 \& \*(Aqlevel x\*(Aq => { \& BusinessHours => \*(Aqwork just in Monday\*(Aq, \& Resolve => { BusinessMinutes => 60 }, \& }, .Ve .PP then \f(CW%RT::ServiceBusinessHours\fR should have the corresponding definition: .PP .Vb 5 \& %RT::ServiceBusinessHours = ( \& \*(Aqwork just in Monday\*(Aq => { \& 1 => { Name => \*(AqMonday\*(Aq, Start => \*(Aq9:00\*(Aq, End => \*(Aq18:00\*(Aq }, \& }, \& ); .Ve .PP Default Business Hours setting is in \f(CW$RT::ServiceBusinessHours\fR{'Default'}. .SS "Defining service levels per queue" .IX Subsection "Defining service levels per queue" In the config you can set per queue defaults, using: .PP .Vb 8 \& %RT::ServiceAgreements = ( \& Default => \*(Aqglobal default level of service\*(Aq, \& QueueDefault => { \& \*(Aqqueue name\*(Aq => \*(Aqdefault value for this queue\*(Aq, \& ... \& }, \& ... \& }; .Ve .SS "AssumeOutsideActor" .IX Subsection "AssumeOutsideActor" When using a Response configuration, the due date is unset when anyone who is not a requestor replies. If it is common for non-requestors to reply to tickets, and this should \fInot\fR satisfy the \s-1SLA,\s0 you may wish to set \&\f(CW\*(C`AssumeOutsideActor\*(C'\fR. This causes the extension to assume that the Response \s-1SLA\s0 has only been met when the owner or AdminCc reply. .PP .Vb 4 \& %RT::ServiceAgreements = ( \& AssumeOutsideActor => 1, \& ... \& }; .Ve .SS "Access control" .IX Subsection "Access control" You can totally hide \s-1SLA\s0 custom field from users and use per queue defaults, just revoke SeeCustomField and ModifyCustomField. .PP If you want people to see the current service level ticket is assigned to then grant SeeCustomField right. .PP You may want to allow customers or managers to escalate thier tickets. Just grant them ModifyCustomField right. .SH "TODO" .IX Header "TODO" .Vb 1 \& * [implemented, TODO: tests for options in the config] default SLA for queues \& \& * [implemented, TODO: tests] add support for multiple b\-hours definitions, \& this could be very helpfull when you have 24/7 mixed with 8/5 and/or \& something like 8/5+4/2 for different tickets(by requestor, queue or \& something else). So people would be able to handle tickets in the right \& order using Due dates. \& \& * [not implemented] tests for AssumeOutsideActor \- need tests for all of the \& conditionals in RT::Action::SLA_SetDue::IsOutsideActor \& \& * [not implemented] WebUI .Ve .SH "DESIGN" .IX Header "DESIGN" .SS "Classes" .IX Subsection "Classes" Actions are subclasses of RT::Action::SLA class that is subclass of RT::Extension::SLA and RT::Action classes. .PP Conditions are subclasses of RT::Condition::SLA class that is subclass of RT::Extension::SLA and RT::Condition classes. .PP RT::Extension::SLA is a base class for all classes in the extension, it provides access to config, generates Business::Hours objects, and other things useful for whole extension. As this class is the base for all actions and conditions then we \s-1MUST\s0 avoid adding methods which overload methods in 'RT::{Condition,Action}' \s-1RT\s0's modules. .SH "NOTES" .IX Header "NOTES" If you run \f(CW\*(C`make initdb\*(C'\fR more than once you will create multiple \s-1SLA\s0 CFs. You can remove these via \s-1RT\s0's \f(CW\*(C`Configuration\->Global\*(C'\fR menu, (both Custom Fields and Scrips). .SH "AUTHOR" .IX Header "AUTHOR" Best Practical Solutions, \s-1LLC\s0 .SH "BUGS" .IX Header "BUGS" All bugs should be reported via email to .PP .Vb 1 \& L .Ve .PP or via the web at .PP .Vb 1 \& L. .Ve .SH "COPYRIGHT" .IX Header "COPYRIGHT" This extension is Copyright (C) 2007\-2014 Best Practical Solutions, \s-1LLC.\s0 .PP This is free software, licensed under: .PP .Vb 1 \& The GNU General Public License, Version 2, June 1991 .Ve