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 This topic is locked, you cannot edit posts or make further replies.  [ 10 posts ] 
Author Message
PostPosted: Wed Feb 06, 2013 11:35 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 28
I wanted a standalone punch station for the free version of Timetrex but it didn't look like anything was available, so I made one myself from a Raspberry Pi ($35) and a Metrologic MS3580 QuantumT Orbit Scanner ($50).

The plan is to give each employee a barcode with their employee number on it. If they just walk up and scan their barcode, it will look up their next punch, set the punch, and then print off a time card for them.

We also plan on having a few tokens with barcodes on them next to the timeclock. Scan a token and then your card to preform special punches. You can scan a "REPORT", "IN", "OUT", "BREAK", "LUNCH" to try to force a certain type of punch.

To set it up, I started with a clean Timetrex installation, and made the first user the account from which the barcode station will log in from.

The server then needed some minor adjustments to work since the free version's API doesn't have a working implemention of getUserPunch();

In APIAuthentication I made it so that user_id one (the administrator account created on first setup) can switchusers by changing
Code:
if ( $this->getPermissionObject()->Check('company','view') AND $this->getPermissionObject()->Check('company','login_other_user') ) {

to
Code:
if ( $this->getCurrentUserObject()->getId() == '1') { 


Then in APIPunch I changed
Code:
if ( is_object($current_station) AND $current_station->checkAllowed( $user_id, $station_id, $station_type ) == TRUE ) {

to
Code:
if ( '1'  == '1' ) {

to allow all stations

And then I commented out the 3 instances of:
Code:
//'station_id' => $current_station->getId(),


That's it for the server. For the client, I put a 2GB SD card in my Raspberry Pi and installed ArchLinux. I set the resolution to 640x480 in config.txt, installed php (I had to enable soap and adjust open_basedir in php.ini), copied the timetrex install folder in /opt, and made an locked down user account. Then I set that account to automatically log into the command line, with these instructions:
https://wiki.archlinux.org/index.php/Au ... al_console

Finally, I set .bash_profile to automatically run my punch card script on boot.

Code:
<?php


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

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

$colors = new Colors();
   
reconnect:
 
    echo "\n" . $colors->getColoredString("Reconnecting to server.....", "white", "red"). "\n";
    $api_session = new TimeTrexClientAPI();
   $api_session->Login( $TIMETREX_USERNAME, $TIMETREX_PASSWORD );
   
   if ( $TIMETREX_SESSION_ID == FALSE ) {
      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\n", "white", "red");
   goto reconnect;
   }
   $punch_data = $result->getResult();
   if($punch_data == false){
    echo $colors->getColoredString("CONNECTION ERROR\n", "white", "red");
   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;
   }
   
   
   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";
    }
   
   //get scanner input on a timer
    $input = fgets_u(STDIN);
   
   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";
   $punchtime = time();
   }
   if (strpos($input,"LUNCH") !== FALSE){
    $punchtype = "Lunch";
   $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\n", "white", "red");
   goto reconnect;
}
$user_data = $result->getResult();
if($user_data  == false){
     echo $colors->getColoredString("CONNECTION ERROR- getResult -> getUser\n", "white", "red");
   goto reconnect;
}
if (is_bool($user_data) == TRUE) {
   echo $colors->getColoredString("\n\nUSER NOT FOUND IN DATABASE!\n\n", "white", "red");
   goto newscan;
}

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

if ($punchtype != "Report"){
 
 
//Switch to the User we scanned in
$auth_obj = new TimeTrexClientAPI( 'Authentication' );
if($auth_obj  == false){
    echo $colors->getColoredString("CONNECTION ERROR - auth_obj\n", "white", "red");
   goto reconnect;
}
$auth_obj->switchUser( $user_data[0]['id'] );
if($auth_obj  == false){
    echo $colors->getColoredString("CONNECTION ERROR - switchUser\n", "white", "red");
   goto reconnect;
}

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

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

$punch_data = $result->getResult();
if($punch_data  == false){
     echo $colors->getColoredString("CONNECTION ERROR - getResult -> getUserPunch\n", "white", "red");
   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;
}

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

$result = $result->getResult();

if ($result == false) {
    echo $colors->getColoredString("\nPLEASE WAIT AT LEAST ONE MINUTE BETWEEN PUNCHES!\n", "white", "red");
   goto reconnect;
}else {
echo "#{$user_data[0]['id']} 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\n", "white", "red");
   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\n", "white", "red");
   goto reconnect;
}

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

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

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

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

//parse and display the CSV file

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

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

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

//echo each line of data
foreach ($csvData as &$value) {
     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);
printf( "% 6.3f",  $total);

//done
goto newscan;
 
         
function fgets_u($pStdn) {
        $pArr = array($pStdn);
        if (false === ($num_changed_streams = stream_select($pArr, $write = NULL, $except = NULL, 10 ))) {
            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);
      }
   }
 
?>


I need to do a bit more testing, but after it is put into production I will post a SD card image of my Raspberry Pi installation.


Top
 Profile  
 
PostPosted: Thu Feb 21, 2013 1:57 pm 
Offline

Joined: Thu Feb 21, 2013 1:55 pm
Posts: 1
That is seriously impressive, and I would love to try the image you have if you would be so kind !

Very well done and fingers crossed I can have a play myself :)


Top
 Profile  
 
PostPosted: Thu Mar 28, 2013 5:19 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 28
I looked into releasing an image, but I can't be sure that I've sanitized all of my personal information off of the image...

The directions posted above are very complete, I would suggest just following those. Feel free to ask if you need any clarifications.

Here is the most updated version of my punch station script:

Code:
<?php


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

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

$colors = new Colors();

reconnect:

$TIMETREX_SESSION_ID= FALSE;
echo "\n" . $colors->getColoredString("Reconnecting to server.....", "white", "red"). "\n";
$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;
    }

    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";
    goto newscan;
}

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

if ($punchtype != "Report") {


   //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";
            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
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);
    }
}


?>


Attachments:
IMAG0597.jpg
IMAG0597.jpg [ 1.33 MiB | Viewed 12079 times ]
IMAG0594.jpg
IMAG0594.jpg [ 1.22 MiB | Viewed 12079 times ]
Top
 Profile  
 
PostPosted: Wed Mar 05, 2014 5:35 am 
Offline

Joined: Wed Jan 16, 2013 2:22 pm
Posts: 28
I recently upgraded from a 5.x version of TimeTrex (on an old Windows XP install) to 7.3.1 (on an Ubuntu 12.04 LTS VM in Proxmox) without any problems.

I would like to note that this modification still works in TimeTrex 7.3.1, but there are a few minor changes.

In APIAuthentication, change two instances of (one is in newSession, the other in switchUser)
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 once instance of
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 one line
Code:
$data['station_id'] = $current_station->getId();

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


TimeTrex has been working great for us, with over 60,000 punches processed through our timeclocks so far.


Top
 Profile  
 
PostPosted: Tue Jun 10, 2014 1:34 pm 
Offline

Joined: Tue Jun 10, 2014 12:49 pm
Posts: 4
Hi,

thanks for sharing the great idea of the standalone punch station. I just set up a prototype with some changes to your original setup

- replaced the bar code scanner by a cheap (10 EUR) 125kHz RFID USB reader
- added a small USB keypad (8 EUR) to enter codes for IN/OUT/BREAK/REPORT
- changed the output to german :)

[img][/http://wiki.system-admin.info/DSC_0027.JPG]

I added a user "punch" that is automatically loged in via /etc/inittab. The user has /home/punch/punch.php as his shell setup via /etc/passwd. This makes sure the application is startet automatically and the user can not reach a regular command prompt.

changes to /etc/inittab:

Code:
# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  <id>:<runlevels>:<action>:<process>
#
# Note that on most Debian systems tty7 is used by the X Window System,
# so if you want to add more getty's go ahead but skip tty7 if you run X.
#
1:2345:respawn:/bin/login -f punch tty1 </dev/tty1 >/dev/tty1 2>&1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6



from /etc/passwd:

Code:
punch:x:1001:1004:,,,:/home/punch:/home/punch/punch.php



punch.php

Code:
#!/usr/bin/php
<?php


require_once('./TimeTrexClientAPI.class.php');

//admin login info
$TIMETREX_URL = 'http://127.0.0.1/timetrex/api/soap/api.php';
$TIMETREX_USERNAME = 'admin';
$TIMETREX_PASSWORD = 'Wr$$dNuW';

$colors = new Colors();

exec("/usr/bin/clear");

reconnect:

$TIMETREX_SESSION_ID= FALSE;
echo "\n" . $colors->getColoredString("Verbindung wird aufgebaut.....", "white", "red"). "\n";
$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("VERBINDUNGSFEHLER", "white", "red");
        echo "\n";
        goto reconnect;
    }
    $punch_data = $result->getResult();
    if ($punch_data == false) {
        echo $colors->getColoredString("VERBINDUNGSFEHLER", "white", "red");
        echo "\n";
        goto reconnect;
    }
    echo "\n\n";
    echo $punch_data['time_stamp'];
    echo "\n\nScanner bereit\n\n";

    if ($punchtype != "Normal") {
        echo $colors->getColoredString("Stempel Art: " . $punchtype , "white", "red");
    } else {
        echo "Stempel Modus: ". $punchtype ;
    }
    echo "\n";
    if ($punchstatus != "Auto") {
        echo $colors->getColoredString("Stempel Richtung: " . $punchstatus , "white", "red");
    } else {
        echo "Stempel Richtung: ". $punchstatus;
    }

    echo "\n\n";

    //skip the padding to leave the last report on the screen
    if ($firsttime == FALSE) {
        echo "\n\n\n";
      echo "Tastaturkürzel (falls notwendig)\n\n";
      echo "<1>  <ENTER>    : Kommt (In)\n";
      echo "<2>  <ENTER>    : Geht (Out)\n";
      echo "<3>  <ENTER>    : Pause (Break)\n";
      echo "<4>  <ENTER>    : Essen (Lunch)\n";
      echo "<5>  <ENTER>    : Bericht (Report)\n";
      echo "<00> <ENTER>    : Automatik\n";
      echo "\n\n";
      echo "Bitte Transponder vor das Lesegerät halten\n";
      echo "\n\n\n\n\n\n\n";
        //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
   $mode_change_flag = "FALSE";
   // make sure NUMLOCK is on
   exec('/usr/bin/setleds -D +num');
    $input = fgets_u(STDIN,10);

    if (strcmp($input,"1") == 0) {
        $punchtype = "Normal";
        $punchstatus = "In";
        $punchtime = time();
      $mode_change_flag = "TRUE";
      $input = "";
    }
    if (strcmp($input,"2") == 0) {
        $punchstatus = "Out";
        $punchtime = time();
      $mode_change_flag = "TRUE";
      $input = "";
    }

    if (strcmp($input,"3") == 0) {
        $punchtype = "Break";
        $punchstatus = "Out";
        $punchtime = time();
      $mode_change_flag = "TRUE";
      $input = "";
    }
    if (strcmp($input,"4") == 0) {
        $punchtype = "Lunch";
        $punchstatus = "Out";
        $punchtime = time();
      $mode_change_flag = "TRUE";
      $input = "";
    }

    if (strcmp($input,"00") == 0) {
        $punchtype = "Normal";
        $punchstatus = "Auto";
      $mode_change_flag = "TRUE";
      $input = "";
    }

    if (strcmp($input,"5") == 0) {
        $punchtype = "Report";
        $punchtime = time();
      $mode_change_flag = "TRUE";
      $input = "";
    }


   if ($mode_change_flag !== FALSE) {
          if (is_numeric($input)) {
             $punchid = (int)$input;
         }
   }

    $firsttime = FALSE;
}

$user_obj = new TimeTrexClientAPI( 'User' );
if ($user_obj  == false) {
    echo $colors->getColoredString("VERBINDUNGSFEHLER - user_obj\n", "white", "red");
    goto reconnect;
}

$result = $user_obj->getUser(array('filter_data' => array('employee_number' => $punchid)));
if ($result == false) {
    echo $colors->getColoredString("VERBINDUNGSFEHLER - getUser", "white", "red");
    echo "\n";
    goto reconnect;
}
$user_data = $result->getResult();
if ($user_data  == false) {
    echo $colors->getColoredString("VERBINDUNGSFEHLER- getResult -> getUser", "white", "red");
    echo "\n";
    goto reconnect;
}
if (is_bool($user_data) == TRUE) {
    echo "\n\n";
    echo $colors->getColoredString("MITARBEITER NICHT GEFUNDEN!", "white", "red");
    echo "\n\n";
    goto newscan;
}

echo "\nMitarbeiterIn gefunden.  Moment...\n";

if ($punchtype != "Report") {


   //Switch to the User we scanned in
    $auth_obj = new TimeTrexClientAPI( 'Authentication' );
    if ($auth_obj  == false) {
        echo $colors->getColoredString("VERBINDUNGSFEHLER - auth_obj", "white", "red");
        echo "\n";
        goto reconnect;
    }
    $auth_obj->switchUser( $user_data[0]['id'] );
    if ($auth_obj  == false) {
        echo $colors->getColoredString("VERBINDUNGSFEHLER - switchUser", "white", "red");
        echo "\n";
        goto reconnect;
    }

    $punch_obj = new TimeTrexClientAPI( 'Punch' );
    if ($punch_obj  == false) {
        echo $colors->getColoredString("VERBINDUNGSFEHLER - punch_obj", "white", "red");
        echo "\n";
        goto reconnect;
    }

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

    $punch_data = $result->getResult();
    if ($punch_data  == false) {
        echo $colors->getColoredString("VERBINDUNGSFEHLER - 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("VERBINDUNGSFEHLER - setUserPunch", "white", "red");
            echo "\n";
            goto reconnect;
        }

        $result = $result->getResult();

        if ($result == false) {
            echo $colors->getColoredString("\nBITTE MIND. EINE MINUTE ZWISCHEN DEN BUCHUNGEN!", "white", "red");
            echo "\n";
            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("VERBINDUNGSFEHLER - BERICHT NICHT VERFÜGBAR", "white", "red");
    echo "\n";
    goto reconnect;
}

//get report
echo "____________________\n\n";
echo "Bericht\n";
echo "____________________\n\n";
$report_obj = new TimeTrexClientAPI( 'PunchSummaryReport' );
if ($report_obj  == false) {
    echo $colors->getColoredString("VERBINDUNGSFEHLER - 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("VERBINDUNGSFEHLER - 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("VERBINDUNGSFEHLER - getPunchSummaryReport", "white", "red");
    echo "\n";
    goto reconnect;
}

$result = $result->getResult();
if ($result  == false) {
    echo $colors->getColoredString("VERBINDUNGSFEHLER - 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], 12);
        echo str_pad ($value[3], 20);
        echo str_pad ($value[4], 12);
        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
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);
    }
}
?>


cu

Carsten


Top
 Profile  
 
PostPosted: Fri Aug 01, 2014 10:34 pm 
Offline

Joined: Fri Aug 01, 2014 10:31 pm
Posts: 11
I have followed this and got it to work. However after the initial clock in, when a user clocks out it is clocking them out and then immediately clocking them back in. Any ideas on what could be causing this?


Top
 Profile  
 
PostPosted: Sat Aug 02, 2014 2:34 pm 
Offline

Joined: Fri Aug 01, 2014 10:31 pm
Posts: 11
Does this still work with most current version? I have tried to get it working ... and it does except it will not switch users (I found a workaround for that) and it double punches on clock out. It is immediately clocking back in after clock out. (I have not found a fix for this yet)


Top
 Profile  
 
PostPosted: Thu Oct 16, 2014 12:06 am 
Offline

Joined: Tue Jun 10, 2014 12:49 pm
Posts: 4
Hi Kendash,


sorry, I didn't look into this forum for some time.

What version of timetrex you are actually running now? Did you try to punch IN/OUT via a connected keyboard or with barcode / RFID etc?


cu


Carsten


Top
 Profile  
 
PostPosted: Sun Oct 19, 2014 9:08 am 
Offline

Joined: Fri Aug 01, 2014 10:31 pm
Posts: 11
I would love to get it to switch users but I never could get it to do that. I have since found a work around for my needs but If I was to ever figure out how to get the userswitch working that would simplify my process.

I am using the latest 7.4.4


Top
 Profile  
 
PostPosted: Sun Nov 02, 2014 10:15 am 
Offline

Joined: Fri Oct 31, 2014 7:59 am
Posts: 1
So did this double punch issue get resolved? This project is highly relevant to my interests. I read your Samba thread as well Kendash, looks like you've put quite a bit of effort into this.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic This topic is locked, you cannot edit posts or make further replies.  [ 10 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:  


Time and Attendance




Powered by phpBB® Forum Software © phpBB Group