Proof of concept: Creating reoccuring tickets for task

Jens Bothe11. Nov 2010 | Best PracticesModifications & Packages

A question asked by my customers quite often is:

“How can we create a reoccuring ticket for tasks like checking the backup?”

As there was no solution inside of the OTRS Framework yet my answer was:

“Sorry, you have to create an e-mail via cron for this.”

An article in the german Linux Magazin put this question back to my mind. (Sorry it is in german..)

So I changed the script ‘ical-daemon’ to my needs. Now the following parameters of the ical file are used:
The ticket itself is created by the script ‘create-ticket.pl’ which will be triggered by ‘ical-daemon’ with the needed parameters.

  • DESCRIPTION: Article Body
  • SUMMARY:        Article and Ticket Subject
  • LOCATION:        Queue Name
  • Ticket created by the daemon:


    Example ics file:

    BEGIN:VCALENDAR
    VERSION:2.0
    PRODID:-//Apple Inc.//iCal 4.0.3//EN
    CALSCALE:GREGORIAN
    BEGIN:VTIMEZONE
    TZID:Europe/Berlin
    BEGIN:DAYLIGHT
    TZOFFSETFROM:+0100
    RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
    DTSTART:19810329T020000
    TZNAME:GMT+02:00
    TZOFFSETTO:+0200
    END:DAYLIGHT
    BEGIN:STANDARD
    TZOFFSETFROM:+0200
    RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
    DTSTART:19961027T030000
    TZNAME:GMT+01:00
    TZOFFSETTO:+0100
    END:STANDARD
    END:VTIMEZONE
    BEGIN:VEVENT
    CREATED:20101111T190648Z
    UID:6B58179D-E1C4-466B-A881-F15A663EE4A7
    DTEND;TZID=Europe/Berlin:20101111T225000
    TRANSP:OPAQUE
    SUMMARY:Please check Backup
    DTSTART;TZID=Europe/Berlin:20101111T230000
    DTSTAMP:20101111T202135Z
    LOCATION:Postmaster
    SEQUENCE:7
    DESCRIPTION:Please check Backup of the following servers:
    - server 1
    - server 2
    - server 3
    END:VEVENT
    END:VCALENDAR

    The modified ical-daemon script:


    #!/usr/bin/perl -w
    ###########################################
    # ical-daemon - Parse .ics files and send
    #               alerts on upcoming events.
    # Mike Schilli, 2010 (m@perlmeister.com)
    # modified by Jens Bothe (jb@otrs.org)
    ###########################################
    use strict;
    #use local::lib;
    use iCal::Parser;
    use Log::Log4perl qw(:easy);
    use App::Daemon qw(daemonize);
    use Sysadm::Install qw(mkd slurp tap);
    use FindBin qw($Bin);

    our $UPDATE_REQUESTED = 0;
    our $ALERT_BEFORE =
    DateTime::Duration->new( minutes => 15 );
    our $CURRENT_DAY      = DateTime->today();
    our @TODAYS_EVENTS    = ();

    my($home)  = glob "~";
    my $admdir = "$home/.ical-daemon";
    my $icsdir = "$admdir/ics";

    mkd $admdir unless -d $admdir;
    mkd $icsdir unless -d $icsdir;

    $App::Daemon::logfile = "$admdir/log";
    $App::Daemon::pidfile = "$admdir/pid";

    if( exists $ARGV[0] and
    $ARGV[0] eq '-q' ) {
    my $pid = App::Daemon::pid_file_read();
    kill 10, $pid; # Send USR1
    exit 0;
    }

    Log::Log4perl->easy_init({
    level => $DEBUG,
    file  => $App::Daemon::logfile
    });

    $SIG{ USR1 } = sub {
    DEBUG "Received USR1";
    $UPDATE_REQUESTED = 1;
    };

    $UPDATE_REQUESTED = 1; # bootstrap

    daemonize();

    while(1) {
    my $now = DateTime->now(
    time_zone => 'local' );

    my $today =
    $now->clone->truncate( to => 'day' );

    if( $UPDATE_REQUESTED or
    $CURRENT_DAY ne $today ) {

    $UPDATE_REQUESTED = 0;
    $CURRENT_DAY      = $today;

    DEBUG "Updating ...";
    @TODAYS_EVENTS    = update( $now );
    DEBUG "Update done.";
    }

    if( scalar @TODAYS_EVENTS ) {
    my $entry         = $TODAYS_EVENTS[0];

    DEBUG "Next event at: $entry->[0]";

    if( $now >
    $entry->[0] - $ALERT_BEFORE ) {
    INFO "Notification: ",
    "$entry->[1] $entry->[0]";
    #      tap "$Bin/ical-notify", $entry->[2], $entry->[1],
    tap "$Bin/create-ticket.pl", $entry->[2], $entry->[1], $entry->[3],
    $entry->[0];
    shift @TODAYS_EVENTS;
    next;
    }
    }

    DEBUG "Sleeping";
    sleep 60;
    }

    ###########################################
    sub update {
    ###########################################
    my($now) = @_;

    my $start = $now->clone->truncate(
    to => 'day' );
    my $tomorrow = $now->clone->add(
    days => 1 );

    my $parser=iCal::Parser->new(
    start => $start,
    end   => $tomorrow );

    my $hash;

    for my $file (<$icsdir/*.ics>) {
    DEBUG "Parsing $file";
    $hash = $parser->parse( $file );
    }

    my $year  = $now->year;
    my $month = $now->month;
    my $day   = $now->day;

    if(! exists $hash->{ events }->{
    $year }->{ $month }->{ $day } ) {
    return ();
    }

    my $events = $hash->{ events }->{
    $year }->{ $month }->{ $day };

    for my $key ( keys %$events ) {
    if( event_is_holiday(
    $events->{ $key } ) ) {
    WARN "No alerts today (holiday)";
    return ();
    }
    }

    my @events = ();

    for my $key ( keys %$events ) {
    next if $now >
    $events->{ $key }->{ DTSTART };
    # already over?

    push @events, [
    $events->{ $key }->{ DTSTART },
    $events->{ $key }->{ DESCRIPTION },
    $events->{ $key }->{ SUMMARY },
    $events->{ $key }->{ LOCATION },
    ];
    }

    @events = sort { $a->[0] <=> $b->[0] }
    @events;

    return @events;
    }

    ###########################################
    sub event_is_holiday {
    ###########################################
    my($event) = @_;

    return undef unless
    exists $event->{ ATTENDEE };

    if( $event->{ ATTENDEE }->[ 0 ]->{ CN }
    eq "US Holidays" ) {
    return 1;
    }
    return 0;
    }

    Script: create-ticket.pl

    #!/usr/bin/perl -w

    use SOAP::Lite( 'autodispatch', proxy => 'http://otrs-server/otrs/rpc.pl' );
    my($subject, $agenda, $queue, $time) = @ARGV;
    my $SOAP_User = 'otrs_test';
    my $SOAP_Pass = 'test_otrs!';

    my $OTRS_Subject = $subject;
    my $OTRS_Body = $agenda;

    my $OTRS_CustomerFrom = 'feedback@otrs.org';
    my $OTRS_Queue = $queue;

    # script
    my $RPC = Core->new();

    # create a new ticket number
    my $TicketNumber = $RPC->Dispatch( $SOAP_User, $SOAP_Pass, 'TicketObject', 'TicketCreateNumber' );
    #print "NOTICE: New Ticket Number is: $TicketNumber\n";
    # create a new ticket
    my %TicketData = (
    TN           => $TicketNumber,
    Title        => $OTRS_Subject,
    Queue        => $OTRS_Queue,
    Lock         => 'unlock',
    Priority     => '3 normal',
    State        => 'new',
    CustomerID   => $OTRS_CustomerFrom,
    CustomerUser => $OTRS_CustomerFrom,
    OwnerID      => 3,
    UserID       => 3,
    );
    my $TicketID = $RPC->Dispatch( $SOAP_User, $SOAP_Pass, 'TicketObject', 'TicketCreate', %TicketData => 1 );
    #print "NOTICE: TicketID is $TicketID\n";

    # create new article
    my $ArticleID = $RPC->Dispatch($SOAP_User, $SOAP_Pass, 'TicketObject', 'ArticleCreate',
    TicketID         => $TicketID,
    ArticleType      => 'phone',                # email-external|email-internal|phone|fax|...
    SenderType       => 'customer',             # agent|system|customer
    From             => $OTRS_CustomerFrom,     # not required but useful
    To               => $OTRS_Queue,            # not required but useful
    ReplyTo          => $OTRS_CustomerFrom,     # not required
    Subject          => $OTRS_Subject,          # required
    Body             => $OTRS_Body,             # required
    Charset          => 'utf-8',
    HistoryType      => 'PhoneCallCustomer',    # EmailCustomer|Move|AddNote|PriorityUpdate|WebRequestCustomer|...
    HistoryComment   => 'Customer called us.',
    UserID           => 3,
    NoAgentNotify    => 0,                      # if you don't want to send agent notifications
    MimeType         => 'text/plain',
    Loop             => 0,                      # auto reject|auto follow up|auto follow up|auto remove
    AutoResponseType => 'auto reply',
    ForceNotificationToUserID => '',
    OrigHeader       => {
    'From' => $OTRS_CustomerFrom,
    'To'   => $OTRS_Queue,
    'Subject' => $OTRS_Subject,
    'Body' => $OTRS_Body,
    },
    );
    #print "NOTICE: ArticleID is $ArticleID\n";

    exit 0;

    You can download the files here

    #5
    Murat Yaman at 04.01.2017, 12:24

    Hello can someone describe where we must place this folders and how we can schedule this via cron?

    #4
    Dani at 17.06.2013, 12:33

    Where do I place the files to work? I have tried many locations, but have not worked Please help me :D

    #3
    Patrick at 13.06.2013, 17:09

    How can i use this Script in OTRS... ? I think over Webservices but i really have no idea :-/ Could you help me ?

    #2
    Easy ticket creation via Generic Interface | OTRS Community Blog at 03.10.2012, 20:25

    [...] This script can also be used with the wrapper of reoccuring task described in the post “Proof of concept: Creating reoccuring tickets for task” [...]

    #1
    Tweets that mention Proof of concept: Creating reoccuring tickets for task - OTRS Community Blog -- Topsy.com at 12.11.2010, 08:02

    [...] This post was mentioned on Twitter by Christopher T. Kuhn, Jens Bothe. Jens Bothe said: Wrote a new blog entry on scheduling task with OTRS http://bit.ly/agP8Yd #otrs Thank you Linux Magazin [...]

    Your email address will not be published. Required fields are marked *