Delicious      Technorati      Blinklist      Furl      Reddit

TimeTrex Time and Attendance

TimeTrex Time and Attendance


* FAQ    * Search
* Login   * Register

All times are UTC - 8 hours [ DST ]




Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Mon Jun 01, 2015 7:33 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
I was going to update my old punch station post, but it looks like it is so old it's now locked (http://forums.timetrex.com/viewtopic.php?f=5&t=5899).

The instructions from the old post still work in V8.0.7. To upgrade my v7 installation, I simply ran the official update, and then applied the changes again.

In APIAuthentication change
Code:
if ( $this->getPermissionObject()->Check('company', 'view') AND $this->getPermissionObject()->Check('company', 'login_other_user') ) {
to
Code:
if ( $this->getCurrentUserObject()->getId() == '1') {


In APIPunch change
Code:
if ( is_object($current_station) AND $current_station->checkAllowed( $user_id, $station_id, $station_type ) == TRUE ) {
to
Code:
if ( '1'  == '1' ) {


and comment out this:
Code:
'station_id' => $current_station->getId(),
so it looks like:
Code:
//'station_id' => $current_station->getId(),


After this, the old punch station script worked without modification. Attached is a newer version with a few tweaks I've added over the years. Now the timeclock directly emails me if someone tries to punch too often, if Timetrex is down, or if various problems occur.

Note: I run Timetrex under Ubuntu in a VM on Proxmox. In version 7, Timetrex would occasionally (once a month) hang up during the automated Proxmox backup. I believe it was caused by heavy disk access during the backup competing with Timetrex. Stopping the Timetrex cron jobs during the proxmox backup window seemed to fix this. I'll be curious to see how 8 behaves.

We currently have 150,000 punches and counting in our database.

Code:
<?php
$RECONNECT = 0;
$LAST_PUNCH = 0;
$LAST_PUNCH_TIME = time();

require_once('../../classes/modules/api/client/TimeTrexClientAPI.class.php');

//admin login info
$TIMETREX_URL = 'http://1.1.1.1:8085/api/soap/api.php';
$TIMETREX_USERNAME = 'admin';
$TIMETREX_PASSWORD = 'admin';

   $colors = new Colors();
   
reconnect:

    $TIMETREX_SESSION_ID= FALSE;
    echo "\n" . $colors->getColoredString("Reconnecting to server..... Attempt " . $RECONNECT, "white", "red"). "\n";
   $RECONNECT = $RECONNECT + 1;
   
   if ($RECONNECT == 5){
   
   
    $cmd = 'echo "Administrator Alert. Error: Over 5 Reconnection Attempts." | mail -S smtp=1.1.1.1 -s "TimeTrex Timeclock" "name@site.com, name@site.com"  > /dev/null 2>/dev/null &';
   exec($cmd);
   
   }
   
    $api_session = new TimeTrexClientAPI();
   $api_session->Login( $TIMETREX_USERNAME, $TIMETREX_PASSWORD );
   
   if ( $TIMETREX_SESSION_ID == FALSE ) {
              sleep(10);
      goto reconnect;
   }
   
     
newscan:
   $punch_obj = new TimeTrexClientAPI( 'Punch' );
   $punchtime = time();
    $punchtype = "Normal";
   $punchstatus = "Auto";
    $punchid = 0;
   $firsttime = TRUE;
 while ($punchid == 0){
   
    if (time() - $punchtime > 10){
           $punchtype = "Normal";
           $punchstatus = "Auto";
   }

    //get time from server and print it
    $result = $punch_obj->getUserPunch();

   if($result == false){
    echo $colors->getColoredString("CONNECTION ERROR", "white", "red");
    echo "\n";
   goto reconnect;
   }
   $punch_data = $result->getResult();
   if($punch_data == false){
    echo $colors->getColoredString("CONNECTION ERROR", "white", "red");
    echo "\n";
   goto reconnect;
   }
   echo "\n\n";
    echo $punch_data['time_stamp'];
    echo "\n\nScanner Ready\n\n";

   
   
    if ($punchtype != "Normal"){
   echo $colors->getColoredString("Punch Type: " . $punchtype , "white", "red");
   } else{
   echo "Punch Type: ". $punchtype ;
   }
   echo "\n";
    if ($punchstatus != "Auto"){
   echo $colors->getColoredString("Punch Direction: " . $punchstatus , "white", "red");
   } else{
    echo "Punch Direction: ". $punchstatus;
   }
   
   $reconnect = 0;
   echo "\n\n";
   
   //skip the padding to leave the last report on the screen
   if ($firsttime == FALSE){
    echo "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
    }


   //get scanner input if over 10 seconds, refresh screen
    $input = fgets_u(STDIN,10);
   
   if (strpos($input,"IN") !== FALSE){
    $punchstatus = "In";
   $punchtime = time();
   }
   if (strpos($input,"OUT") !== FALSE){
    $punchstatus = "Out";
   $punchtime = time();
   }
   
   if (strpos($input,"BREAK") !== FALSE){
    $punchtype = "Break";
    $punchstatus = "Out";
   $punchtime = time();
   }
   if (strpos($input,"LUNCH") !== FALSE){
    $punchtype = "Lunch";
    $punchstatus = "Out";
   $punchtime = time();
   }
   
   if (strpos($input,"NORMAL") !== FALSE || strpos($input,"RESET") !== FALSE ||  strpos($input,"CLEAR") !== FALSE){
        $punchtype = "Normal";
       $punchstatus = "Auto";
   }
   
   if (strpos($input,"REPORT") !== FALSE){
    $punchtype = "Report";
   $punchtime = time();
   }
     
   if (is_numeric($input)){
   $punchid = (int)$input;
   }   
   
   $firsttime = FALSE;
}
 
$user_obj = new TimeTrexClientAPI( 'User' );

if($user_obj  == false){

    echo $colors->getColoredString("CONNECTION ERROR - user_obj\n", "white", "red");
   goto reconnect;
}

$result = $user_obj->getUser(array('filter_data' => array('employee_number' => $punchid)));
   
if($result == false){
     echo $colors->getColoredString("CONNECTION ERROR - getUser", "white", "red");
    echo "\n";
   goto reconnect;
}
$user_data = $result->getResult();

if($user_data  == false){
     echo $colors->getColoredString("CONNECTION ERROR- getResult -> getUser", "white", "red");
    echo "\n";
   goto reconnect;
}
if (is_bool($user_data) == TRUE) {
    echo "\n\n";
   echo $colors->getColoredString("USER NOT FOUND IN DATABASE!", "white", "red");
    echo "\n\n";
   
   $cmd = 'echo "Error: User ID not found! #';
   $cmd .= (string)$punchid;
   $cmd .=  '" | mail -S smtp=1.1.1.1 -s "TimeTrex Timeclock" name@site.com  > /dev/null 2>/dev/null &';
   exec($cmd);



   goto newscan;
}

echo "\nUser found.  Working...\n";

if ($punchtype != "Report"){

 
 
if($user_data[0]["status"]  != "Active"){
     echo $colors->getColoredString("INACTIVE USER", "white", "red");
    echo "\n";
   
   $cmd = 'echo "Error: User ID inactive! ';
   $cmd .= "#{$user_data[0]['employee_number']}: {$user_data[0]['last_name']}, {$user_data[0]['first_name']}\n\n";
   $cmd .=  '" | mail -S smtp=1.1.1.1 -s "TimeTrex Timeclock" name@site.com  > /dev/null 2>/dev/null &';
   exec($cmd);
   goto reconnect;
}
 
 
//Switch to the User we scanned in
$auth_obj = new TimeTrexClientAPI( 'Authentication' );


if($auth_obj  == false){
    echo $colors->getColoredString("CONNECTION ERROR - auth_obj", "white", "red");
    echo "\n";
   goto reconnect;
}
$auth_obj->switchUser( $user_data[0]['id'] );


if($auth_obj  == false){
    echo $colors->getColoredString("CONNECTION ERROR - switchUser", "white", "red");
    echo "\n";
   goto reconnect;
}

$punch_obj = new TimeTrexClientAPI( 'Punch' );

if($punch_obj  == false){
    echo $colors->getColoredString("CONNECTION ERROR - punch_obj", "white", "red");
    echo "\n";
   goto reconnect;
}

$result = $punch_obj->getUserPunch();
if($result  == false){
    echo $colors->getColoredString("CONNECTION ERROR - getUserPunch", "white", "red");
    echo "\n";
   goto reconnect;
}


$punch_data = $result->getResult();

if($punch_data  == false){
     echo $colors->getColoredString("CONNECTION ERROR - getResult -> getUserPunch", "white", "red");
    echo "\n";
   goto reconnect;
}


//override the automaticlly generated punch
if ($punchstatus == "In"){
 $punch_data['status_id']=10;
}
if ($punchstatus == "Out"){
$punch_data['status_id']=20;
}

if ($punchtype == "Break"){
 $punch_data['type_id']=30;
}
if ($punchtype == "Lunch"){
$punch_data['type_id']=20;
}



if ($punchtype != "Report"){

$result = $punch_obj->setUserPunch($punch_data);
if($result  == false){
     echo $colors->getColoredString("CONNECTION ERROR - setUserPunch", "white", "red");
    echo "\n";
   goto reconnect;
}

$result = $result->getResult();

if ($result == false) {
    echo $colors->getColoredString("\nPLEASE WAIT AT LEAST ONE MINUTE BETWEEN PUNCHES!", "white", "red");
    echo "\n";
   
   $cmd = 'echo "Error: Cannot generate punch - User likely double punched! ';
   $cmd .= "#{$user_data[0]['employee_number']}: {$user_data[0]['last_name']}, {$user_data[0]['first_name']}\n\n";
   $cmd .=  '" | mail -S smtp=1.1.1.1 -s "TimeTrex Timeclock" name@site.com  > /dev/null 2>/dev/null &';
   exec($cmd);
   
   goto reconnect;
}else {
echo "#{$user_data[0]['employee_number']} Punch Complete\n";
}

}

$api_session->Logout();
}

//Generate the punch report
//log back in as admin

$api_session->Login( $TIMETREX_USERNAME, $TIMETREX_PASSWORD );
if ( $TIMETREX_SESSION_ID == FALSE ) {
    echo $colors->getColoredString("CONNECTION ERROR - REPORT LOGIN FAILED", "white", "red");
    echo "\n";
   goto reconnect;
}

//get report
echo "____________________\n\n";
echo "Punch Summary Report\n";
echo "____________________\n\n";
$report_obj = new TimeTrexClientAPI( 'PunchSummaryReport' );
if($report_obj  == false){
     echo $colors->getColoredString("CONNECTION ERROR - report_obj", "white", "red");
    echo "\n";
   goto reconnect;
}

$config = $report_obj->getTemplate('by_employee+punch_summary+total_time')->getResult();
if($config  == false){
     echo $colors->getColoredString("CONNECTION ERROR - getTemplate", "white", "red");
    echo "\n";
   goto reconnect;
}

//adjust template
$config['-1010-time_period']['time_period'] = 'this_pay_period';
$config['employee_number'] = $user_data[0]['employee_number'];


//let the server generate the report
$result = $report_obj->getPunchSummaryReport($config , 'csv' );
if($result  == false){
     echo $colors->getColoredString("CONNECTION ERROR - getPunchSummaryReport", "white", "red");
    echo "\n";
   goto reconnect;
}

$result = $result->getResult();
if($result  == false){
     echo $colors->getColoredString("CONNECTION ERROR - getResult -> getPunchSummaryReport", "white", "red");
    echo "\n";
   goto reconnect;
}

//parse and display the CSV file

//decode report
$input = base64_decode($result['data']);
//split the line breaks
$input = str_replace("\"", "", $input);
$csvData = explode( "\n", $input);
//split at the commas
foreach ($csvData as &$value) {
     $value = explode(',', $value);
}

$total = 0;  // tally of total hours worked

//print table headers
echo "#{$user_data[0]['employee_number']}: {$user_data[0]['last_name']}, {$user_data[0]['first_name']}\n\n";

//echo each line of data
foreach ($csvData as &$value) {
if(isset($value[2]) && isset($value[3]) &&isset($value[4]) && isset($value[5]) && isset($value[6])) {
     echo str_pad ($value[2], 10);
    echo str_pad ($value[3], 20);
    echo str_pad ($value[4], 10);
    echo str_pad ($value[5], 20);
     if (is_numeric($value[6]) ) {
      $total = $total + (float)$value[6];
      if ((float)$value[6] != 0 ){
      printf( "% 6.3f", $value[6]);
    }else{
    echo str_pad($value[6], 10);
    }
    echo "\n";
}   
}
//print total hours worked
echo str_pad (" ", 60);
echo $colors->getColoredString(sprintf( "% 6.3f",  $total), "white", "green");
//done

if ($punchtype != "Report"){

if ($LAST_PUNCH == $punchid and $LAST_PUNCH_TIME + 90 > time()){
    $cmd = 'echo "Warning: Punches too close together - User likely double punched! ';
   $cmd .= "#{$user_data[0]['employee_number']}: {$user_data[0]['last_name']}, {$user_data[0]['first_name']}\n\n";
   $cmd .=  '" | mail -S smtp=1.1.1.1 -s "TimeTrex Timeclock" name@site.com  > /dev/null 2>/dev/null &';
   exec($cmd);
}

//done
$LAST_PUNCH = $punchid;
$LAST_PUNCH_TIME = time();

}


goto newscan;
 
         
function fgets_u($pStdn,$delay) {
        $pArr = array($pStdn);
        if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL,$delay ))) {
            print("\$ 001 Socket Error : UNABLE TO WATCH STDIN.\n");
            return FALSE;
        } elseif ($num_changed_streams > 0) {
                return trim(fgets($pStdn, 1024));
        }
    }
?>

<?php
 
   class Colors {
      private $foreground_colors = array();
      private $background_colors = array();
 
      public function __construct() {
         // Set up shell colors
         $this->foreground_colors['black'] = '0;30';
         $this->foreground_colors['dark_gray'] = '1;30';
         $this->foreground_colors['blue'] = '0;34';
         $this->foreground_colors['light_blue'] = '1;34';
         $this->foreground_colors['green'] = '0;32';
         $this->foreground_colors['light_green'] = '1;32';
         $this->foreground_colors['cyan'] = '0;36';
         $this->foreground_colors['light_cyan'] = '1;36';
         $this->foreground_colors['red'] = '0;31';
         $this->foreground_colors['light_red'] = '1;31';
         $this->foreground_colors['purple'] = '0;35';
         $this->foreground_colors['light_purple'] = '1;35';
         $this->foreground_colors['brown'] = '0;33';
         $this->foreground_colors['yellow'] = '1;33';
         $this->foreground_colors['light_gray'] = '0;37';
         $this->foreground_colors['white'] = '1;37';
 
         $this->background_colors['black'] = '40';
         $this->background_colors['red'] = '41';
         $this->background_colors['green'] = '42';
         $this->background_colors['yellow'] = '43';
         $this->background_colors['blue'] = '44';
         $this->background_colors['magenta'] = '45';
         $this->background_colors['cyan'] = '46';
         $this->background_colors['light_gray'] = '47';
      }
 
      // Returns colored string
      public function getColoredString($string, $foreground_color = null, $background_color = null) {
         $colored_string = "";
 
         // Check if given foreground color found
         if (isset($this->foreground_colors[$foreground_color])) {
            $colored_string .= "\033[" . $this->foreground_colors[$foreground_color] . "m";
         }
         // Check if given background color found
         if (isset($this->background_colors[$background_color])) {
            $colored_string .= "\033[" . $this->background_colors[$background_color] . "m";
         }
 
         // Add string and end coloring
         $colored_string .=  $string . "\033[0m";
 
         return $colored_string;
      }
 
      // Returns all foreground color names
      public function getForegroundColors() {
         return array_keys($this->foreground_colors);
      }
 
      // Returns all background color names
      public function getBackgroundColors() {
         return array_keys($this->background_colors);
      }
   }
 
?>


Top
 Profile  
 
PostPosted: Wed Jun 03, 2015 4:54 am 
Offline

Joined: Wed Apr 29, 2015 8:29 pm
Posts: 25
Wow! Impressive! Nice job mate!

Will this work on other brand of barcode scanner?



---------------
WK


Top
 Profile  
 
PostPosted: Wed Jun 03, 2015 6:37 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
I used barcode scanners that show up as a keyboard, so anything (barcode, RFID, etc) that can type into the console will work.

The barcodes themselves are simply the employee number printed out with a few leading zeros. For more permanent employees we make plastic cards on an Fargo ID printer. Temps get laminated card stock. It works well for us because we can make temporary cards on the fly, or even make blank cards (and blank users in Timetrex) in bulk ahead of time to hand out and fill in later.

As for the barcodes, I suggest using Code 128. When we used Code 39 barcodes, we had occasional mis-scans.

With Code 128, we still get one or two mis-scans (normally a missing digit) per year (verified by security camera footage and logs), but I think this might be due to a pi USB fault or possibly a scanner fault. Either way, 1 fault out of 60,000 is doing pretty good.

I'd suggest getting familiar with PHP (if you aren't already) and modifying the script to suit your own needs. That way you can make it do whatever you want. For example, at one point we had a receipt printer that would automatically print out timecards, but that turned out to be a waste of paper. The on screen display was more popular.


Top
 Profile  
 
PostPosted: Wed Jun 03, 2015 9:15 pm 
Offline

Joined: Wed Apr 29, 2015 8:29 pm
Posts: 25
Wow! speechless!

This is exactly i was looking for. I think i'll try this out using a regular CPU , some cheap barcode scanner and keyboard. We go paperless and just a display on the monitor.

Unfortunately, i'm just a php beginner, so i'm totally relying on your guides. Do you have any summarized step by step guide exactly how you put it altogether? Thanks mate, this is a huge help in my part.

Thanks,

WK


Top
 Profile  
 
PostPosted: Mon Jun 08, 2015 6:08 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
If you aren't comfortable with setting it up yourself, I'd suggest either sticking to the default installation, or paying for the professional version and buying a solution.

You don't want to run into a problem down the road and be unable to fix it.


Top
 Profile  
 
PostPosted: Tue Jun 09, 2015 3:17 am 
Offline

Joined: Wed Apr 29, 2015 8:29 pm
Posts: 25
Hi!

Everything is in default installation, I just want a quick punching station for free since most of our volunteer workers are older, they cannot stand logging in with so many steps. We are a non-profit institution, we can't afford to buy professional license annually.

All I want is a barcode standalone quick punch station without printing. I think your implementation is so close of what i'm trying to do.


Thanks,

WK


Top
 Profile  
 
PostPosted: Mon Jun 22, 2015 8:21 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
Note: I found out this morning that v8 has an automatic update feature that is turned on by default. This does not play well with modified versions of timetrex.

To fix the warnings, I manually updated to 8.0.8 using the Linux installer from sourceforge, re-applied my modifications, and then disabled automatic updates by adding the following line to timetrex.ini.php:

[other]
disable_auto_upgrade = TRUE


Top
 Profile  
 
PostPosted: Sat Dec 26, 2015 5:26 pm 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
Note: The above modifications still work in 9.0.5, but the station line that needs to be commented out looks slightly different.

Code:
$data['station_id'] = $current_station->getId();


Top
 Profile  
 
PostPosted: Thu May 25, 2017 4:28 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 29
Note: The above modifications still work in 10.6, but I noticed updates can no longer be manually downloaded from sourceforge.

I get them from here:
https://www.timetrex.com/onsite_communi ... p=download


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 9 posts ] 

All times are UTC - 8 hours [ DST ]


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron


Time and Attendance




Powered by phpBB® Forum Software © phpBB Group