Proof of concept: Creating reoccuring tickets for task

Jens Bothe, 11. 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 *

    This site uses cookies. By continuing to use the site, you agree to the use of cookies. More information

    The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

    Close