Change Log of e-Punch Card

v. 1.2 2025-08-18 Kaizen Completed for PunchCard.phpr

Add the attendance list page to display all attendance record by “employee_name”

BEFORE AFTER

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Go to “Tables” tab and enable “attendance”.
  2. Delete “Attendance” in the “Menu editor”.

  3. Go to “Query” tab, select “attendance” in Table list, click on “SQL” tab and paste below query:-
    SELECT
        record_id,
        `date`,
        time_in,
        time_out_lunch,
        time_in_lunch,
        time_out,
        time_in_overtime,
        time_out_overtime,
        remark,
        employee_id
    FROM attendance
    ORDER BY `date` DESC
  4. Go to “Pages” tab, select “attendance” in Tables list and set as below:-
  5. Go to “Designer” tab, select “attendance” in Tables list, click on “list” tab, click “employee_id” field, click “View As/Edit As” and edit as below:-

  6. Select “punchcard” in Tables list, click on “list” tab and insert a new “Custom Button”. Name it as “View_Attendance”.

  7. Paste below code in “Client Before” tab:-

    var employee_id = row.getFieldValue("employee_id");
    var employee_name = row.getFieldValue("employee_name");
    var valueToPass = employee_id;
    var popupUrl = "attendance_list.php?q=(employee_id~equals~" + valueToPass + ")";
    
    var childPopup = Runner.displayPopup({
        url: popupUrl,
        header: "Attendance Record for " + employee_name,
        width: 1200,
        height: 650,
        afterCreate: function(childPopup) {
            window.parent.popup.close();
        }
    });
    
    return false;
  8. Click on “View Attendance” and edit its properties like below:-
  9. Go to “Editor” tab, double-click on the logo and rename it to version “1.2”.

 

Display only active employee in “E-Punch Card”

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Go to “Query” tab, select “punchcard” in Tables list, click on “SQL” tab and paste below query:-
    SELECT
        e.employee_id,
        e.employee_name,
        (SELECT time_in FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in,
        (SELECT time_out_lunch FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out_lunch,
        (SELECT time_in_lunch FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in_lunch,
        (SELECT time_out FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out,
        (SELECT time_in_overtime FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in_overtime,
        (SELECT time_out_overtime FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out_overtime,
        (SELECT `remark` FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS `remark`
    FROM employee e
    WHERE e.active = 1
    ORDER BY e.employee_name ASC

 

v. 1.2 2025-08-18 Beta Testing Complete for PunchCard.phpr

TEST OBJECTIVE: Can user view their attendance record by their own name?

TESTING METHODOLOGY TEST RESULT
  1. Open “E-PUNCH CARD VERSION 1.2”, click on any “view” icon beside the “Employee Name” field to view the employee’s attendance record.

 


 

v. 1.1 2025-06-10 Kaizen Completed for PunchCard.phpr

To add tabs 1 to 31 in http://hpc-6305/punchcard/punchcard_list.php?orderby=aemployee_name in order to  view the date of attendance

The “Select” button will only work when the date is on today. On other dates, the button will be disabled.

BEFORE AFTER
http://hpc-6305/ams/attendance_list.php  

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Go to “Tables” tab and click “Create custom View”. Name the custom view as “1”.
  2. Go to “Query” tab and add below query:-
    SELECT 
         e.employee_name, 
         a.`date`, 
         a.time_in, 
         a.time_out_lunch, 
         a.time_in_lunch, 
         a.time_out, 
         a.time_in_overtime, 
         a.time_out_overtime 
    FROM attendance AS a 
    LEFT OUTER JOIN employee AS e ON a.employee_id = e.employee_id 
    WHERE (YEAR(a.`date`) = YEAR(CURRENT_DATE()) && 
          MONTH(a.`date`) = MONTH(CURRENT_DATE()) && 
          DAY(a.`date`) = "01") 
    ORDER BY e.employee_name
  3. Go to “Pages” tab and check only “List page”.
  4. Go to “Designer” tab and remove “timestamp_snippet” and “SELECT” button.
  5. Go to “Events” tab and click “Erase event code” in “Before display” and “JavaScript OnLoad event”.
  6. Create another 30 custom views and change the custom view’s name and the query in the red text below accordingly:-
    SELECT 
         e.employee_name, 
         a.`date`, 
         a.time_in, 
         a.time_out_lunch, 
         a.time_in_lunch, 
         a.time_out, 
         a.time_in_overtime, 
         a.time_out_overtime 
    FROM attendance AS a 
    LEFT OUTER JOIN employee AS e ON a.employee_id = e.employee_id 
    WHERE (YEAR(a.`date`) = YEAR(CURRENT_DATE()) && 
          MONTH(a.`date`) = MONTH(CURRENT_DATE()) && 
          DAY(a.`date`) = "01") 
    ORDER BY e.employee_name
  7. Go to “Tables” tab and click “Menu editor” button.
  8. Add a new group called “Day”.

  9. Move all 31 custom views inside “Day” group.
  10. Go to “Designer” tab, select “punchcard” in Tables list and set the page layout as below:-
  11. Click “apply to…” button and select “All list pages in the project”.


 

To rename “PUNCH CARD VERSION 1.0.1” to “E-Punch Card version 1.1”

BEFORE AFTER

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Go to “Editor” tab, double-click on “PUNCH CARD VERSION 1.0.1” and rename it to “E-Punch Card version 1.1”.
    Note: Due to the theme setting, the name of the logo will be all uppercase.

 

v. 1.1 2025-06-10 Beta Testing Completed for PunchCard.phpr

TEST OBJECTIVE: Do all 31 custom views only shows the attendance list without “SELECT” button?

TESTING METHODOLOGY TEST RESULT
  1. Expand “Day” menu and check for each date.
  2. All pages should not have the “SELECT” button inside it except the main page of punchcard.
 


 

v. 1.0 2025-02-25 Kaizen Completed for PunchCard.phpr

Create a separate project for punch card

BEFORE AFTER

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Create a new project and name it as “PunchCard”.
  2. Enable only “attendance” table in “Tables” tab.
  3. Go to “Pages” tab and enable only “Add new” page.
  4. Go to “Events” tab -> “attendance” -> “Add page” -> “JavaScript OnLoad event” and paste below code:-

 

Add a Dashboard

  • Add a dashboard (main page), showing list of employee with their time in and out in grid view.
  • Each employee can click on his name on the list and will load the “attendance_add.php” web page to punch card.
  • After employee click on “Save” button”, the web page will return to the grid view and showing the latest time in or time out.
EMPLOYEE NAME MORNING IN MORNING OUT AFTERNOON IN AFTERNOON OUT EVEINING IN EVEINING OUT
Wati 08:32:00 12:35:00 14:00:00      
Mazura 08:31:00 12:31:00 14:02:00      
Ms. Wong 08:30:00 12:30:00      

 

BEFORE AFTER

MODIFICATION in PHPRunner or cPanel or PHPMyAdmin

  1. Modify “attendance” table in phpMyAdmin as below:-
  2. Go to “Tables” tab and create a new custom view for “punchcard”.
  3. Go to “Query” tab and paste below query:-
    SELECT 
         e.employee_id, 
         e.employee_name, 
         (SELECT time_in FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in, 
         (SELECT time_out_lunch FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out_lunch, 
         (SELECT time_in_lunch FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in_lunch, 
         (SELECT time_out FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out, 
         (SELECT time_in_overtime FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_in_overtime, 
         (SELECT time_out_overtime FROM attendance WHERE employee_id = e.employee_id AND `date` = CURDATE()) AS time_out_overtime 
    FROM employee e 
    ORDER BY e.employee_name ASC
  4. Go to “Pages” tab and enable only “List page” and “Add new” page.
  5. Go to “Misc” tab and set the landing page to punchcard’s “list” page.
  6. Rename “Time In Lunch” field to “Time In After Lunch”.
  7. Add custom button “Punch”.
    • go to “Designer” tab, select “list” tab, click “Insert…” dropdown and select “Custom Button” and name it as “SELECT”.
    • change the tri-part events for the “Select” button as below:-
      • Client Before
        params["employee_id"] = row.getFieldValue("employee_id"); 
         params["employee_name"] = row.getFieldValue("employee_name");

      • Server
        $_SESSION["employee_id"] = $params["employee_id"]; 
        $_SESSION["employee_name"] = $params["employee_name"];

      • Client After
        var popup = Runner.displayPopup({ 
              url: Runner.pages.getUrl("punchcard","add"), 
              width: 450, 
              height: 315, 
              header: 'Punch In' 
        });

    • Go to “Events” tab:-
      • click on “Add page” -> After record added” and paste below code:
        $pageObject->setProxyValue('saved', true); 
        echo "<!doctype html>";

      • click on “Add page” -> JavaScript OnLoad event” and paste below code:
        if((proxy['saved'])) { 
             // close popup 
             window.parent.close(); 
             // refresh list page 
             window.parent.location.reload(); 
        }

  8. Display date and time in “list” page.
    • go to “Designer” tab and insert a new “Code Snippet”, name it as “timestamp_snippet” and paste below code:

      echo "<div><span class='btn btn-info' style='font-size:25px; font-weight:bold; cursor:default !important;'>".date('l, d-m-Y')."</span>". 
      " <span class='timestamp btn btn-info' style='font-size:25px; font-weight:bold; cursor:default !important;'>".date('h:i:s a')."</span></div>";

    • go to “Events” tab -> “List page” -> “JavaScript OnLoad event” and paste below code:
      setInterval(clock, 1000); 
      function clock() { 
           var clockDiv = document.querySelector(".timestamp"); 
           var date = new Date(); 
           var tick = date.toLocaleTimeString(); 
           clockDiv.textContent = tick; 
      }

  9. Add “Status” dropdown.
    • go to “Designer” tab -> “Add” tab, add a new “Code Snippet” name “status_snippet” and paste below code:

      $str= "<select id='status' name='status' style='width:380px; display:inline-block;' class='form-control'>". 
      "<option value=\"\">Please select</option>"; 
      
      $strSQL = "SELECT * FROM attendance WHERE employee_id=".$_SESSION["employee_id"]. " AND `date`=CURDATE()"; 
      $rs = db_query($strSQL); 
      
      if (!mysqli_num_rows($rs)) { 
           $str.="<option value='time_in'>Time In</option>"; 
           $str.="<option value='time_out_lunch'>Time Out Lunch</option>"; 
           $str.="<option value='time_in_lunch'>Time In After Lunch</option>"; 
           $str.="<option value='time_out'>Time Out</option>"; 
           $str.="<option value='time_in_overtime'>Time In Overtime</option>"; 
           $str.="<option value='time_out_overtime'>Time Out Overtime</option>"; 
      } else { 
           while ($data = db_fetch_array($rs)) { 
                if ($data["time_in"] == "") 
                     $str.="<option value='time_in'>Time In</option>"; 
                if ($data["time_out_lunch"] == "") 
                     $str.="<option value='time_out_lunch'>Time Out Lunch</option>"; 
                if ($data["time_in_lunch"] == "") 
                     $str.="<option value='time_in_lunch'>Time In After Lunch</option>"; 
                if ($data["time_out"] == "") 
                     $str.="<option value='time_out'>Time Out</option>"; 
                if ($data["time_in_overtime"] == "") 
                     $str.="<option value='time_in_overtime'>Time In Overtime</option>"; 
                if ($data["time_out_overtime"] == "") 
                     $str.="<option value='time_out_overtime'>Time Out Overtime</option>";
           } 
      } 
      
      $str.="</select>"; 
      echo $str;

    • go to “Events” tab -> “Add page” -> “JavaScript OnLoad event” and paste below code:
      this.on('beforeSave', function(formObj, fieldControlsArr, pageObj) { 
           var val = $("#status").val(); 
           formObj.baseParams['status'] = val; 
      });

  10. Display “Employee Name” in “Add” page.
    • go to “Events” tab -> “Add page” -> “Process record values” and paste below code:
      $values['employee_name'] = $_SESSION["employee_name"];

  11. Create a “Custom add”.
    • go to “Events” tab -> “Add page” -> “Custom add” and paste below code:
      $attSQL = DB::Query("SELECT * FROM attendance WHERE `date` = CURDATE() AND employee_id = " . $_SESSION["employee_id"]); 
      $data = $attSQL->fetchAssoc(); 
      $status = strtolower($_POST["status"]); 
      
      // If user already add a record, update the record 
      if ($data) { 
           $update = array(); 
           $update[$status] = strftime("%H:%M:%S"); 
           DB::Update("attendance", $update, "record_id=" . $data["record_id"]); 
      // Else insert a new record 
      } else { 
           $data = array(); 
           $data["date"] = strftime("%Y-%m-%d"); 
           $data[$status] = strftime("%H:%M:%S"); 
           $data["employee_id"] = 
           $_SESSION["employee_id"]; 
           DB::Insert("attendance", $data); 
      } 
      
      // Place event code here. 
      // Use "Add Action" button to add code snippets. 
      
      return false;

  12. Add highlight for absentees and late punch.
    • go to “Events” tab -> “List page” -> “List page: After record processed” and paste below code:
      if ($data["time_in"] == "" && $data["time_in_lunch"] == "") 
           $record["employee_name_css"] = 'background:#fc4f37;color:#ffffff;'; 
      
      if($data['time_in'] > "08:30:59") 
           $record["time_in_css"] = 'color:red;'; 
      
      if($data['time_in_lunch'] > "13:30:59") 
           $record["time_in_lunch_css"] = 'color:red;';


 

v. 1.0 2025-02-25 Beta Testing Completed

TEST OBJECTIVE: Does the “Status” dropdown only shows the status with empty time?

TESTING METHODOLOGY TEST RESULT
  1. Click “SELECT” button for any employee.
  2. Select “Time In” and click “PUNCH”.
  3. Click “SELECT” button again. The “Time In” will not be displayed inside the dropdown anymore.

 

How To Automatically Run MySQL Dump in Windows and Linux to Backup MySQL Database

Windows

  1. Create a batch file “sweetcoc_ams_backup.bat” for mysqldump. Copy below code into the batch file:-
    @echo off
    REM set mysqldump path
    SET mysqldump_path="C:\wamp64\bin\mysql\mysql5.7.26\bin\mysqldump.exe"
    REM credentials to connect to MySQL server
    SET mysql_user=root
    SET mysql_password=
    REM backup storage location
    SET backup_folder="C:\wamp64\www\database_backups"
    REM backup file name
    SET backup_name=%backup_folder%\sweetcoc_ams_%DATE:~-4%-%DATE:~7,2%-%DATE:~4,2%.sql
    REM create backup
    "C:\wamp64\bin\mysql\mysql5.7.26\bin\mysqldump.exe" -u %mysql_user%
    sweetcoc_ams > %backup_name%
  2. Create a new Task Scheduler that executes the batch file.

 

Linux

  1. Create a new PHP file and copy below code into it.
    <?php
    
    ini_set('display_errors', 1);
    ini_set('display_startup_errors', 1);
    error_reporting(E_ALL);
    
    $database = '*****';
    $user = '*****';
    $pass = '*****';
    $host = '*****';
    //$dir = dirname(__FILE__) . '/dump.sql';
    $dir = dirname(__FILE__);
    
    echo "Backing up database to {$dir}.";
    echo "\n";
    
    exec("mysqldump --user={$user} --password={$pass} --host={$host} --no-tablespaces {$database} | zip > \${HOME}/database_backup/{$database}_`date '+%Y-%m-%d_%H:%M'`.sql.zip", $output);
    
    echo "\n";
    echo "Backup completed.";
    
    ?>
  2. Create a new Cron Job and point to the path where the PHP file is saved.
    /usr/local/bin/php
    /home4/sweetcoc/database_backup/mysqldump.php
  3. The Cron Job will save the database as below:-

 

Restoring a Back-Up Database

  1. Go to “D:\” drive in UBS-SERVER.
  2. Compress “AMS Back-Up” folder to “AMS Back-Up.zip”.
  3. Copy “AMS Back-Up.zip” into “C:\wamp64\www\” folder in HP-6305-W7PRO and extract it.
  4. After extracted, move all folders inside “AMS Back-Up” folder to the root folder of “C:\wamp64\www\”. The folder hierarchy should be as below:-
  5. Go to “Start”, search for “wampserver” and run “Wampserver64”.
  6. Wait and ensure the icon is green in “System Tray” that indicates all services are running.
  7. If not then click on “Wampserver64” icon and select “Restart All Services”.
  8. Click on Windows “System Tray” dropdown -> click “Wamserver64” icon -> click “phpMyAdmin”. “phpMyAdmin” will be opened on the browser.
  9. Enter the “username = root” and leave the password empty. Click “Go”.
  10. Click on “sweetcoc_ams” database -> click “Import”.
  11. Click “Choose file”.
  12. Browse “C:\wamp64\www\database_backups”, sort the files by “Date modified” and open the latest SQL file.
  13. Leave everything as it is and click “Go”.
  14. Go to browser and open “http://localhost/punchcard”.
  15. Finally HP-6305-W7PRO” will have the latest version of “E-Punch Card” and “sweetcoc_ams” database.

How to Upgrade SERVERLINK

  1. Firstly, create a restore point.
  2. Open SERVERLINK, in “HOME”, click on the update.
  3. Let SERVERLINK download the update.
  4. After the download has been completed, a popup will appear. Click “Yes”.
  5. Click “Next” on each Setup.

    Note: if you choose “Only dowload setup (do not install)” , then the setup file is downloaded into this folder “C:\Users\…\AppData\Local\Temp\UpdateRelease.exe“. Run the “UpdateRelease.exe” at a later date.

  6. Restart UBS-SERVER.
  7. Finally, check the version displayed is the latest version (s.c.).

Comparison of E-mail API used in PHP

Runner_Mail() PHPMailer() PHP Mail()
SMTP, user name, password, port, etc. are set inside the PHPRunner UI

PHPMailer() is called by Runner_Mail()

SMTP is set inside the PHP code itself

SMTP is set in “PHP.ini”
<?php

require_once(“include/dbcommon.php”);

 

$email = “t1@mobitek.my”;

$msg = “”;

$subject = “New data record”;

 

$msg.= “Message: [Message]\r\n”;

$msg.= “Recipient: Recipient\r\n”;

$msg.= “Date/Time: DateTimeQueue\r\n”;

runner_mail(array(‘to’ => ‘$email’, ‘subject’ => $subject, ‘body’ => $msg));

?>

<?php
include_once(‘libs/phpmailer/class.phpmailer.php’);
include_once(‘libs/phpmailer/class.smtp.php’);$mail = new PHPMailer( true );
// Mail settings
$mail->isSMTP();   //Send using SMTP
$mail->Host = ‘mail.sweetco.com.my’;   //Set the SMTP server to send through
$mail->SMTPAuth = true;   //Enable SMTP authentication
$mail->Username = ‘factory@sweetco.com.my‘;   //SMTP username
$mail->Password = ‘2022@Beranang@Factory’;   //SMTP password
//$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;        //Enable implicit TLS encryption
$mail->Port = 587;   //TCP port to connect to; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
$mail->setFrom(‘support@mobitek.my‘, ‘MOBITEK Support’);
$mail->isHTML(false);$mail->To = “t1@mobitek.my”;
$mail->Subject = “This is Subject”;
$mail->Body = “This the body”;
$mail->Send();?>
Open “php.ini” and search for “smtp” (there are no entries for no username and password)

 

[mail function]
; For Win32 only.
; http://php.net/smtp
SMTP = localhost
; http://php.net/smtp-port
smtp_port = 25

; For Win32 only.
; http://php.net/sendmail-from
sendmail_from =“admin@wampserver.invalid”

; For Unix only.  You may supply arguments as well (default: “sendmail -t -i”).
; http://php.net/sendmail-path
;sendmail_path =

; Force the addition of the specified parameters to be passed as extra parameters
; to the sendmail binary. These parameters will always replace the value of
; the 5th parameter to mail().
;mail.force_extra_parameters =

; Add X-PHP-Originating-Script: that will include uid of the script followed by the filename
mail.add_x_header = On

; The path to a log file that will log all mail() calls. Log entries include
; the full path of the script, line number, To address and headers.
;mail.log =
; Log mail to syslog (Event Log on Windows).
;mail.log = syslog

MOBITEK Q25 4G Modem Can Use IP Address instead of COM Port Number

TEST OBJECTIVE TESTING METHODOLOGY TEST RESULT
Can hyper terminal connect to MOBITEK Q25 4G Modem via IP address instead of COM port and run “hyper terminal test“?
  1. Connect MOBITEK Q25 4G Modem  to LAN via LAN port.
  2. Assign IP address to Q25 using USR-TCP232 to be in the same subnet of the LAN. For this example:
    • the gateway is “192.168.10.1”
    • set the IP address for Q25 in this subnet “192.168.10.???”
    • Get the “Module port” of Q25 in USR-TCP232
  3. Run hyper terminal and connect using “TCP/IP (Winsock)”.
  4. Enter the “Host address” and “Port number”
  5. Type “AT” to Hyper Terminal to see if Q25 is responding
  • 860147050425139
  • 860147050425154

How to Implement Log-In Page using “Database” for a Web Application

  1. Edit “Email settings…” in “Misc” tab.
  2. Add new table “users” in “Security” tab.
  3. Set “Dynamic permissions” in “Security” tab. Add a new user.
  4. Build and run the PHPRunner project in localhost. Log in using the username and password added previously. Let the PHPRunner project open in localhost.
  5. Go to PHPRunner project again. Enable “Password hashing (encryption)” in “Registration and passwords…”.
  6. Build and run PHPRunner project again in localhost.
  7. Go to “Admin Area”.
  8. Go to “Add/Edit users”, edit the password. To use back the same password, first change the password to another password. Save it and then edit it back to change to the original password.

MOBITEK Q25 Can Use Internet Application and Send SMS at the Same Time

TEST OBJECTIVE TESTING METHODOLOGY TEST RESULT
Can MOBITEK Q25 connect to internet and send out SMS at the same time?
  1. Connect to internet, refer to https://mobitek-system.com/blog/category/iot/mobitek-q25-4g-modem/
  2. Use hyper terminal  to send out SMS (hyper-terminal test as per QC).
  3. Do not close the COM port in hyper terminal, keep it open (connected). Open web browser and visit www.mobitek.my
TEST 1

 

TEST 2

USR-VCOM for MOBITEK S80 and MOBITEK Q25 Works in Windows 11

TEST OBJECTIVE TESTING METHODOLOGY TEST RESULT
Does MOBITEK S80’s USR-VCOM (ELTIMA virtual serial port) support Windows 11?
  1. Install  USR-VCOM in VM-Windows 11 :-

  2. Do “Hyper-Terminal” or “AT-OK” test.
USR-VCOM version = 3.7.1.520

Does MOBITEK Q25’s USR-VCOM (ELTIMA virtual serial port) support Windows 11?
  1. Install  USR-VCOM in VM-Windows 11 :-

  2. Do “Hyper-Terminal” or “AT-OK” test.
USR-VCOM version = 3.7.1.520