diff --git a/core-ext/config.base.php b/core-ext/config.base.php
index 4a420dac..79d79506 100644
--- a/core-ext/config.base.php
+++ b/core-ext/config.base.php
@@ -9,9 +9,9 @@ define('HOME_LINK_ADMIN', CLIENT_BASE_URL."?g=admin&n=dashboard&m=admin_Admin");
define('HOME_LINK_OTHERS', CLIENT_BASE_URL."?g=modules&n=dashboard&m=module_Personal_Information");
//Version
-define('VERSION', '15.0.OS');
-define('CACHE_VALUE', '15.0.OS');
-define('VERSION_DATE', '07/02/2016');
+define('VERSION', '15.3.OS');
+define('CACHE_VALUE', '15.3.OS');
+define('VERSION_DATE', '12/03/2016');
if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');}
if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');}
diff --git a/core-ext/db_upgrade/upgrade_v15.0.OS_to_v15.2.OS.sql b/core-ext/db_upgrade/upgrade_v15.0.OS_to_v15.2.OS.sql
new file mode 100644
index 00000000..f1bc7db9
--- /dev/null
+++ b/core-ext/db_upgrade/upgrade_v15.0.OS_to_v15.2.OS.sql
@@ -0,0 +1,23 @@
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('System: Default Country', '0', 'Set the default Country','[ "value", {"label":"Country","type":"select2","remote-source":["Country","code","name"]}]');
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Overtime Calculation Class', 'BasicOvertimeCalculator', 'Set the method used to calculate overtime','["value", {"label":"Value","type":"select","source":[["BasicOvertimeCalculator","BasicOvertimeCalculator"],["CaliforniaOvertimeCalculator","CaliforniaOvertimeCalculator"]]}]');
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Overtime Start Hour', '8', 'Overtime calculation will start after an employee work this number of hours per day, 0 to indicate no overtime', ''),
+ ('Attendance: Double time Start Hour', '12', 'Double time calculation will start after an employee work this number of hours per day, 0 to indicate no double time', '');
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Work Week Start Day', '0', 'Set the starting day of the work week','["value", {"label":"Value","type":"select","source":[["0","Sunday"],["1","Monday"],["2","Tuesday"],["3","Wednesday"],["4","Thursday"],["5","Friday"],["6","Saturday"]]}]');
+
+INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `type`,`report_group`) VALUES
+('Overtime Report', 'This report list all employee attendance entries by employee with overtime calculations', '[\r\n[ "employee", {"label":"Employee","type":"select2multi","allow-null":true,"null-label":"All Employees","remote-source":["Employee","id","first_name+last_name"]}],\r\n[ "date_start", {"label":"Start Date","type":"date"}],\r\n[ "date_end", {"label":"End Date","type":"date"}]\r\n]', 'OvertimeReport', '["employee","date_start","date_end"]', 'Class','Time Management');
+
+INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `type`,`report_group`) VALUES
+('Overtime Summary Report', 'This report list all employee attendance entries by employee with overtime calculation summary', '[\r\n[ "employee", {"label":"Employee","type":"select2multi","allow-null":true,"null-label":"All Employees","remote-source":["Employee","id","first_name+last_name"]}],\r\n[ "date_start", {"label":"Start Date","type":"date"}],\r\n[ "date_end", {"label":"End Date","type":"date"}]\r\n]', 'OvertimeSummaryReport', '["employee","date_start","date_end"]', 'Class','Time Management');
+
+Alter table `Employees` modify column `joined_date` date default '0000-00-00';
+Alter table `Employees` modify column `confirmation_date` date default '0000-00-00';
+Alter table `Employees` modify column `termination_date` date default '0000-00-00';
+Alter table `Employees` modify column `birthday` date default '0000-00-00';
diff --git a/core-ext/scripts/icehrm_master_data.sql b/core-ext/scripts/icehrm_master_data.sql
index 526c488e..77de1aa7 100644
--- a/core-ext/scripts/icehrm_master_data.sql
+++ b/core-ext/scripts/icehrm_master_data.sql
@@ -798,6 +798,25 @@ REPLACE INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`,
'["employee","date_start","date_end","status"]', 'Class');
+INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `type`,`report_group`) VALUES
+ ('Overtime Report', 'This report list all employee attendance entries by employee with overtime calculations', '[\r\n[ "employee", {"label":"Employee","type":"select2multi","allow-null":true,"null-label":"All Employees","remote-source":["Employee","id","first_name+last_name"]}],\r\n[ "date_start", {"label":"Start Date","type":"date"}],\r\n[ "date_end", {"label":"End Date","type":"date"}]\r\n]', 'OvertimeReport', '["employee","date_start","date_end"]', 'Class','Time Management');
+
+INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `type`,`report_group`) VALUES
+ ('Overtime Summary Report', 'This report list all employee attendance entries by employee with overtime calculation summary', '[\r\n[ "employee", {"label":"Employee","type":"select2multi","allow-null":true,"null-label":"All Employees","remote-source":["Employee","id","first_name+last_name"]}],\r\n[ "date_start", {"label":"Start Date","type":"date"}],\r\n[ "date_end", {"label":"End Date","type":"date"}]\r\n]', 'OvertimeSummaryReport', '["employee","date_start","date_end"]', 'Class','Time Management');
+
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Overtime Calculation Class', 'BasicOvertimeCalculator', 'Set the method used to calculate overtime','["value", {"label":"Value","type":"select","source":[["BasicOvertimeCalculator","BasicOvertimeCalculator"],["CaliforniaOvertimeCalculator","CaliforniaOvertimeCalculator"]]}]');
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Overtime Start Hour', '8', 'Overtime calculation will start after an employee work this number of hours per day, 0 to indicate no overtime', ''),
+ ('Attendance: Double time Start Hour', '12', 'Double time calculation will start after an employee work this number of hours per day, 0 to indicate no double time', '');
+
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Attendance: Work Week Start Day', '0', 'Set the starting day of the work week','["value", {"label":"Value","type":"select","source":[["0","Sunday"],["1","Monday"],["2","Tuesday"],["3","Wednesday"],["4","Thursday"],["5","Friday"],["6","Saturday"]]}]');
+
+
+
INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
('Company: Logo', '', '','[ "value", {"label":"Logo","type":"fileupload","validation":"none"}]'),
('Company: Name', 'Sample Company Pvt Ltd', 'Update your company name - For updating company logo copy a file named logo.png to /app/data/ folder', ''),
diff --git a/readme.md b/readme.md
index 49bc45b2..7f72632e 100644
--- a/readme.md
+++ b/readme.md
@@ -532,6 +532,21 @@ That way you can attach each and every project to a client.
Under employee projects tab you can assign projects to employees. You need to add projects to employees to enable them to add time against
these projects in time-sheets.
+Release note v15.2
+------------------
+
+### Features
+ * Overtime Reports
+ * Overtime calculation for california
+
+### Fixes
+ * Fix issue: uncaught error when placeholder value is empty
+ * Log email sending success status
+ * Fix broken longer company name issue
+ * Make the application accessible when client on an intranet with no internet connection
+ * Fix issue: when a module is disabled other modules depend on it stops working
+
+
Release note v15.0
------------------
diff --git a/src/api/Base.js b/src/api/Base.js
index 9628b9bd..2abfff35 100644
--- a/src/api/Base.js
+++ b/src/api/Base.js
@@ -1678,7 +1678,10 @@ IceHRMBase.method('fillForm', function(object, formId, fields) {
if(placeHolderVal == undefined || placeHolderVal == null){
placeHolderVal = "";
}else{
- placeHolderVal = placeHolderVal.replace(/(?:\r\n|\r|\n)/g, '
');
+ try{
+ placeHolderVal = placeHolderVal.replace(/(?:\r\n|\r|\n)/g, '
');
+ }catch(e){}
+
}
@@ -2160,3 +2163,12 @@ IceHRMBase.method('generateOptions', function (data) {
return options;
});
+
+IceHRMBase.method('isModuleInstalled', function (type, name) {
+ if(modulesInstalled == undefined || modulesInstalled == null){
+ return false;
+ }
+
+ return (modulesInstalled[type+"_"+name] == 1);
+});
+
diff --git a/src/classes/AbstractModuleManager.php b/src/classes/AbstractModuleManager.php
index 3f7e3824..94191c92 100644
--- a/src/classes/AbstractModuleManager.php
+++ b/src/classes/AbstractModuleManager.php
@@ -194,5 +194,19 @@ abstract class AbstractModuleManager{
$this->modelClasses[] = $className;
}
+ protected function addHistoryGeneric($type, $table, $refName, $refId, $field, $oldValue, $newValue){
+ $eh = new $table();
+ $eh->type = $type;
+ $eh->$refName = $refId;
+ $eh->field = $field;
+ $eh->user = BaseService::getInstance()->getCurrentUser()->id;
+ $eh->old_value = $oldValue;
+ $eh->new_value = $newValue;
+ $eh->created = date("Y-m-d H:i:s");
+ $eh->updated = date("Y-m-d H:i:s");
+
+ $eh->Save();
+ }
+
}
\ No newline at end of file
diff --git a/src/classes/BaseService.php b/src/classes/BaseService.php
index 5e56cd7d..e56f2248 100644
--- a/src/classes/BaseService.php
+++ b/src/classes/BaseService.php
@@ -45,6 +45,7 @@ class BaseService{
var $moduleManagers = null;
var $emailSender = null;
var $user = null;
+ var $historyManagers = array();
private static $me = null;
@@ -89,17 +90,23 @@ class BaseService{
$queryData = array();
if(!empty($filterStr)){
$filter = json_decode($filterStr, true);
-
- if(!empty($filter)){
- foreach($filter as $k=>$v){
- LogManager::getInstance()->info($filterStr);
- if($v == '__myid__'){
- $v = $this->getCurrentProfileId();
- }
- $query.=" and ".$k."=?";
- $queryData[] = $v;
- }
- }
+
+
+ if(!empty($filter)){
+ LogManager::getInstance()->debug("Building filter query");
+ if(method_exists($obj,'getCustomFilterQuery')){
+ LogManager::getInstance()->debug("Method: getCustomFilterQuery exists");
+ $response = $obj->getCustomFilterQuery($filter);
+ $query = $response[0];
+ $queryData = $response[1];
+ }else{
+ LogManager::getInstance()->debug("Method: getCustomFilterQuery not found");
+ $defaultFilterResp = $this->buildDefaultFilterQuery($filter);
+ $query = $defaultFilterResp[0];
+ $queryData = $defaultFilterResp[1];
+ }
+
+ }
}
if(empty($orderBy)){
@@ -112,13 +119,17 @@ class BaseService{
if(in_array($table, $this->userTables)){
$cemp = $this->getCurrentProfileId();
if(!empty($cemp)){
- $signInMappingField = SIGN_IN_ELEMENT_MAPPING_FIELD_NAME;
- $list = $obj->Find($signInMappingField." = ?".$query.$orderBy, array_merge(array($cemp),$queryData));
+ $signInMappingField = SIGN_IN_ELEMENT_MAPPING_FIELD_NAME;
+ LogManager::getInstance()->debug("Query: ".$signInMappingField." = ?".$query.$orderBy);
+ LogManager::getInstance()->debug("Query Data: ".print_r(array_merge(array($cemp),$queryData),true));
+ $list = $obj->Find($signInMappingField." = ?".$query.$orderBy, array_merge(array($cemp),$queryData));
}else{
$list = array();
}
}else{
+ LogManager::getInstance()->debug("Query: "."1=1".$query.$orderBy);
+ LogManager::getInstance()->debug("Query Data: ".print_r($queryData,true));
$list = $obj->Find("1=1".$query.$orderBy,$queryData);
}
@@ -136,19 +147,19 @@ class BaseService{
if(empty($v)){
continue;
}
- $vArr = json_decode($v);
- if(is_array($vArr)){
- if(empty($vArr)){
+ if(is_array($v)){
+ if(empty($v)){
continue;
}
- $v = $vArr;
$length = count($v);
for($i=0; $i<$length; $i++){
- $query.=$k." like ?";
+
if($i == 0){
$query.=" and (";
}
+
+ $query.=$k." like ?";
if($i < $length -1){
$query.=" or ";
@@ -477,7 +488,7 @@ class BaseService{
}
}
}
- return $obj;
+ return $obj->postProcessGetData($obj);
}
return null;
}
@@ -1065,6 +1076,37 @@ class BaseService{
return true;
+ }
+
+ public function isModuleAllowedForGivenUser($moduleManagerObj, $user){
+ $moduleObject = $moduleManagerObj->getModuleObject();
+
+ //Check if the module is disabled
+ if($moduleObject['status'] == 'Disabled'){
+ return false;
+ }
+
+ //Check if user has permissions to this module
+ //Check Module Permissions
+ $modulePermissions = BaseService::getInstance()->loadModulePermissions($moduleManagerObj->getModuleType(), $moduleObject['name'],$user->user_level);
+
+
+ if(!in_array($user->user_level, $modulePermissions['user'])){
+
+ if(!empty($user->user_roles)){
+ $userRoles = json_decode($user->user_roles,true);
+ }else{
+ $userRoles = array();
+ }
+ $commonRoles = array_intersect($modulePermissions['user_roles'], $userRoles);
+ if(empty($commonRoles)){
+ return false;
+ }
+
+ }
+
+ return true;
+
}
public function getGAKey(){
@@ -1123,12 +1165,27 @@ class BaseService{
if(empty($this->moduleManagers)){
$this->moduleManagers = array();
}
- $this->moduleManagers[] = $moduleManager;
+ $moduleObject = $moduleManager->getModuleObject();
+ $this->moduleManagers[$moduleManager->getModuleType()."_".$moduleObject['name']] = $moduleManager;
}
public function getModuleManagers(){
- return $this->moduleManagers;
+ return array_values($this->moduleManagers);
}
+
+ public function getModuleManagerNames(){
+ $keys = array_keys($this->moduleManagers);
+ $arr = array();
+ foreach($keys as $key){
+ $arr[$key] = 1;
+ }
+
+ return $arr;
+ }
+
+ public function getModuleManager($type, $name){
+ return $this->moduleManagers[$type."_".$name];
+ }
public function setEmailSender($emailSender){
$this->emailSender = $emailSender;
@@ -1173,8 +1230,116 @@ class BaseService{
return $dept->timezone;
}
+
+ public function setupHistoryManager($type, $historyManager){
+ $this->historyManagers[$type] = $historyManager;
+ }
+
+ public function addHistoryItem($historyManagerType, $type, $refId , $field, $oldVal, $newVal){
+ if(isset($this->historyManagers[$historyManagerType])){
+ return $this->historyManagers[$historyManagerType]->addHistory($type, $refId , $field, $oldVal, $newVal);
+ }
+ return false;
+ }
+
+ public function getItemFromCache($class, $id){
+ $data = MemcacheService::getInstance()->get($class."-".$id);
+ if($data !== false){
+ return unserialize($data);
+ }
+
+ $obj = new $class();
+ $obj->Load("id = ?",array($id));
+ if($obj->id != $id){
+ return null;
+ }
+
+ MemcacheService::getInstance()->set($class."-".$id, serialize($obj), 10 * 60);
+
+ return $obj;
+
+ }
}
+
+class MemcacheService {
+
+ private $connection = null;
+ public static $openConnections = array();
+ private static $me = null;
+
+ private function __construct(){}
+
+ public static function getInstance(){
+ if(self::$me == null){
+ self::$me = new MemcacheService();
+ }
+
+ return self::$me;
+ }
+
+
+ private function connect() {
+
+ if($this->connection == null) {
+ $this->connection = new Memcached();
+ $this->connection->addServer(MEMCACHE_HOST, MEMCACHE_PORT);
+
+ if(!$this->isConnected()) {
+ $this->connection = null;
+ } else {
+ self::$openConnections[] = $this->connection;
+ }
+ }
+ return $this->connection;
+ }
+
+ private function isConnected(){
+ $statuses = $this->connection->getStats();
+ return isset($statuses[$this->memcacheHost.":".$this->memcachePort]);
+ }
+
+ private function compressKey($key) {
+ return crc32(APP_DB.$key).md5(CLIENT_NAME);
+ }
+
+ public function set($key, $value, $expiry = 3600) {
+ $key = $this->compressKey($key);
+ $memcache = $this->connect();
+
+ if (!empty($memcache) && $this->isConnected()) {
+ $ok = $memcache->set($key, $value, time() + $expiry);
+ if(!$ok) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+
+ public function get($key) {
+ $key = $this->compressKey($key);
+ $memcache = $this->connect();
+ if(!empty($memcache) && $this->isConnected()) {
+ return $memcache->get($key);
+ } else {
+ return false;
+ }
+ }
+
+ public function close() {
+ if($this->connection != null) {
+ if($this->isConnected()) {
+ $this->connection->quit();
+ }
+ $this->connection = null;
+ }
+ }
+}
+
+
+
class IceConstants{
const AUDIT_AUTHENTICATION = "Authentication";
const AUDIT_ADD = "Add";
@@ -1186,4 +1351,8 @@ class IceConstants{
const NOTIFICATION_LEAVE = "Leave Module";
const NOTIFICATION_TIMESHEET = "Time Module";
const NOTIFICATION_TRAINING = "Training Module";
+}
+
+interface HistoryManager{
+ public function addHistory($type, $refId, $field, $oldValue, $newValue);
}
\ No newline at end of file
diff --git a/src/classes/EmailSender.php b/src/classes/EmailSender.php
index 72678dc8..3006acf0 100644
--- a/src/classes/EmailSender.php
+++ b/src/classes/EmailSender.php
@@ -40,7 +40,7 @@ abstract class EmailSender{
array(),
array(),
array()
- );
+ );
}
}
@@ -281,7 +281,9 @@ class SMTPEmailSender extends EmailSender{
$mail = $smtp->send($toEmail, $headers, $body);
-
+ if (PEAR::isError($mail)) {
+ LogManager::getInstance()->info("SMTP Error Response:".$mail->getMessage());
+ }
return $mail;
}
diff --git a/src/classes/FileService.php b/src/classes/FileService.php
index a5da64e9..2ce63c1f 100644
--- a/src/classes/FileService.php
+++ b/src/classes/FileService.php
@@ -41,17 +41,22 @@ class FileService{
public function getFromCache($key){
try{
+ /*
if(empty($this->memcache)){
$this->memcache = new Memcached();
$this->memcache->addServer("127.0.0.1", 11211);
}
-
$data = $this->memcache->get($key);
+ */
+
+ $data = MemcacheService::getInstance()->get($key);
+
if(!empty($data)){
return $data;
}
return null;
+
}catch(Exception $e){
return null;
}
diff --git a/src/css/style.css b/src/css/style.css
index 87eedef3..748975df 100644
--- a/src/css/style.css
+++ b/src/css/style.css
@@ -651,4 +651,14 @@ table.dataTable{
border-radius: 0px;
-moz-border-radius: 0px;
-webkit-border-radius: 0px;
+}
+
+.logoResponsive{
+ background: #3c8dbc !important;
+ text-align: left !important;
+ width:50% !important;
+}
+
+@media screen and (min-width: 0px) and (max-width: 600px) {
+ .logoResponsive { display: none !important;}
}
\ No newline at end of file
diff --git a/src/fileupload_page.php b/src/fileupload_page.php
index e57ce0de..546c7c7c 100644
--- a/src/fileupload_page.php
+++ b/src/fileupload_page.php
@@ -14,9 +14,9 @@ if($_REQUEST['file_type']=="image"){
?>