7 use WWW
::OrangeHRM
::Client
;
22 orangehrm - Command line client for OrangeHRM
30 Set or show time sheet in OrangeHRM system.
34 Without any options, it will show time sheet for current month.
37 =head2 Options for configuration
39 These options can be retrieved from configuration file.
45 Base URL where OrangeHRM instance is running.
47 =item B<--username USER>
49 User name to log in as. If not specified, it will be asked when needed.
51 =item B<--password PASSWORD>
53 Password to use. If not specified, it will be asked when needed.
58 =head2 Options for showing a time sheet
62 =item B<--year NUMBER>
64 Year of Gregorian calendar, default is today.
66 =item B<--month NUMBER>
68 Month of year, counts from 1, default is today.
73 =head2 Options for filling a time sheet
77 =item B<--year NUMBER>
79 Year of Gregorian calendar, default is today.
81 =item B<--month NUMBER>
83 Month of year, counts from 1, default is today.
87 Day of month, counts from 1, default is today.
89 =item B<--from HH::MM>
95 Begining of working time. Use C<boot> for boot time. Use C<now> for current
104 End of working time. Use C<boot> for boot time. Use C<now> for current time.
106 =item B<--break HH:MM>
108 Vacant part in the working time for purpose of working break.
110 =item B<--doctor HH:MM>
112 Vacant part in the working time for purpose of medical check.
114 =item B<--comment STRING>
116 Free comment to the day.
120 Specify if you are on bussines trip on this day.
124 Negation of B<--trip> option. Working hours are filled as at-work by default.
125 This option is usefull only to flip the trip state to work when using
130 Partial modification. With this option, only records with explicit option will
131 be changed. By default, unspecified arguments reset corresponding records to
132 their default values.
137 =head2 Options for submitting a time sheet
143 Submit current month's time sheet for review.
145 =item B<--year NUMBER>
147 Year of Gregorian calendar, default is today.
149 =item B<--month NUMBER>
151 Month of year, counts from 1, default is today.
153 =item B<--comment STRING>
155 Free comment to the submission.
160 =head2 Options for debugging
166 Dump sent HTTP requests and other useful data.
181 Show program version.
187 =head2 F<~/.orangehrm>
191 url = https://redhat.orangehrm.com/
192 samlidp = https://saml.redhat.com/
193 samlout = https://example.redhat.com/bye
197 If L<LWP::Authen::Negotiate> Perl module is installed, and a valid Kerberos
198 ticket granting ticket is available, user name and password are not needed in
203 # Return boot HH:MM time of day specified as argument. Otherwise return undef.
204 sub get_boot_datetime
{
205 my $day = shift->clone()->truncate(to
=> 'day');
208 User
::Utmp
::utmpname
(User
::Utmp
::WTMP_FILE
);
209 for my $entry (User
::Utmp
::getut
()) {
210 if ($entry->{'ut_type'} != User
::Utmp
::BOOT_TIME
() or
211 !exists $entry->{'ut_time'} or !defined $entry->{'ut_time'}) {
214 my $entry_time = DateTime
->from_epoch(epoch
=> $entry->{'ut_time'});
215 my $entry_day = $entry_time->clone()->truncate(to
=> 'day');
216 if (!DateTime
->compare($day, $entry_day)) {
217 if (!defined $boot or 0 > DateTime
->compare($entry_time, $boot)) {
223 $boot = sprintf('%02d:%02d', (localtime($boot->epoch))[2,1]);
229 # Callback function for passing username and password;
230 sub ask_credentials
{
231 my ($prompt, $is_password) = @_;
237 my $value = ReadLine
(0);
242 chomp $value if (defined $value);
247 my ($now, $day, $month, $year);
248 # Translate time specification by word to HH::MM. It operates on $_.
250 if (!defined) { return; }
253 } elsif ($_ eq 'boot') {
254 $_ = get_boot_datetime
(DateTime
->new(
255 year
=> $year, month
=> $month, day
=> $day
258 die "Could not determine boot time for $year-$month-$day.\n";
263 my $config_file = File
::Spec
->catfile($ENV{HOME
}//'/', '.orangehrm');
265 my %configuration = (
266 url
=> 'https://redhat.orangehrm.com/',
274 my ($help, $debug, $version,
275 $from, $to, $break, $doctor, $comment, $trip, $work, $amend,
277 my ($minutes, $hours);
278 ($minutes, $hours, $day, $month, $year) = (localtime)[1, 2, 3, 4, 5];
281 $now = WWW
::OrangeHRM
::Client
::normalize_time
($hours . ':' . $minutes);
284 if (-f
$config_file) {
285 my $cfg = Config
::Tiny
->new->read($config_file);
287 print STDERR
'Could not parse `', $config_file,
288 ' configuration file: ', $Config::Tiny
::errstr
, "\n";
291 for (keys %{$cfg->{_
}}) {
292 $configuration{$_} = $cfg->{_
}->{$_};
297 'url=s' => \
$configuration{url
},
298 'username=s' => \
$configuration{username
},
299 'password=s' => \
$configuration{password
},
301 'month=i' => \
$month,
305 'break=s' => \
$break,
306 'doctor=s' => \
$doctor,
307 'comment=s' => \
$comment,
311 'submit' => \
$submit,
313 'version' => \
$version,
315 ) or pod2usage
(-exitstatus
=> 1, -verbose
=> 1);
317 pod2usage
(-exitstatus
=> 0, -verbose
=> 2);
320 print $WWW::OrangeHRM
::Client
::VERSION
, "\n";
323 if (!defined $configuration{url
}) {
324 pod2usage
(-exitstatus
=> 1, -verbose
=> 1,
325 -message
=> "Missing configuration!\n");
327 if (!$amend and (!defined $from xor !defined $to)) {
328 pod2usage
(-exitstatus
=> 1, -verbose
=> 1,
329 -message
=> "Missing options!\n");
332 if (((defined $from or defined $to or $amend) and defined $submit)
333 or ($trip and $work)) {
334 pod2usage
(-exitstatus
=> 1, -verbose
=> 1,
335 -message
=> "Conflicting options!\n");
341 map translate_time
, ($from, $to);
342 if (defined $comment) {
343 $comment = decode
(locale
=> $comment);
347 my $automaton = WWW
::Mechanize
->new(
352 WWW
::OrangeHRM
::Client
::debug_http
($automaton);
356 if (!WWW
::OrangeHRM
::Client
::log_in
($automaton, \
%configuration,
357 \
&ask_credentials
)) {
358 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
359 'Could not log in!');
361 print "Logged in.\n";
363 if (!WWW
::OrangeHRM
::Client
::time_sheet
($automaton)) {
364 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
365 'Could not get time sheet!');
368 my $date = WWW
::OrangeHRM
::Client
::time_sheet_date
($automaton);
369 if (!defined $date or !($date eq "$year-$month")) {
370 if (!WWW
::OrangeHRM
::Client
::time_sheet_change
($automaton, $year, $month)) {
371 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
372 'Could not change time sheet!');
376 if (defined $from or defined $to or $amend) {
377 if (!WWW
::OrangeHRM
::Client
::time_sheet_set_day
($automaton, $day,
378 $from, $to, $break, $doctor, $comment, $trip, $amend)) {
379 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
380 "Could not fill day #$day into time sheet!");
382 if (!WWW
::OrangeHRM
::Client
::time_sheet_save
($automaton)) {
383 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
384 "Could not save time sheet!");
386 } elsif (defined $submit) {
387 if (!WWW
::OrangeHRM
::Client
::time_sheet_submit
($automaton, $comment)) {
388 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
389 "Could not submit time sheet!");
392 if (!WWW
::OrangeHRM
::Client
::time_sheet_show
($automaton)) {
393 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
394 "Could not parse time sheet!");
399 if (!WWW
::OrangeHRM
::Client
::log_out
($automaton, \
%configuration)) {
400 WWW
::OrangeHRM
::Client
::fatal_error
($automaton, $debug,
401 'Could not log out!');
403 print "Logged out.\n";
411 Copyright © 2012, 2013, 2014, 2015, 2017, 2019 Petr Písař <ppisar@redhat.com>.
415 This is free software. You may redistribute copies of it under the terms of
416 the GNU General Public License L<http://www.gnu.org/licenses/gpl.html>.
417 There is NO WARRANTY, to the extent permitted by law.