Sync changes v29.0.0 from IceHrmPro (https://icehrm.com/purchase-icehrmpro)
This commit is contained in:
@@ -33,8 +33,7 @@ class AttendanceActionManager extends SubActionManager
|
||||
//Find any open punch
|
||||
$attendance = new Attendance();
|
||||
$attendance->Load(
|
||||
"employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? and (out_time is NULL
|
||||
or out_time = '0000-00-00 00:00:00')",
|
||||
"employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? and out_time is NULL",
|
||||
array($employee->id,$date)
|
||||
);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
namespace Classes;
|
||||
|
||||
use Model\BaseModel;
|
||||
use Utils\LogManager;
|
||||
|
||||
abstract class AbstractModuleManager
|
||||
@@ -254,7 +255,17 @@ abstract class AbstractModuleManager
|
||||
protected function addModelClass($className)
|
||||
{
|
||||
$this->modelClasses[] = $className;
|
||||
BaseService::getInstance()->addModelClass($className, $this->moduleObject['model_namespace']."\\".$className);
|
||||
$classWithNamespace = $this->moduleObject['model_namespace']."\\".$className;
|
||||
BaseService::getInstance()->addModelClass($className, $classWithNamespace);
|
||||
/** @var BaseModel $modelClass */
|
||||
$modelClass = new $classWithNamespace();
|
||||
if ($modelClass->isCustomFieldsEnabled()) {
|
||||
$objectName = $modelClass->getObjectName();
|
||||
BaseService::getInstance()->addCustomFieldClass(
|
||||
$className,
|
||||
(null === $objectName)? $className : $objectName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function addHistoryGeneric($type, $table, $refName, $refId, $field, $oldValue, $newValue)
|
||||
@@ -278,4 +289,12 @@ abstract class AbstractModuleManager
|
||||
{
|
||||
BaseService::getInstance()->addCalculationHook($code, $name, $class, $method);
|
||||
}
|
||||
|
||||
public function install()
|
||||
{
|
||||
}
|
||||
|
||||
public function uninstall()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use Employees\Common\Model\EmployeeApproval;
|
||||
use FieldNames\Common\Model\CustomField;
|
||||
use FieldNames\Common\Model\FieldNameMapping;
|
||||
use Metadata\Common\Model\CalculationHook;
|
||||
use Model\BaseModel;
|
||||
use Model\DataEntryBackup;
|
||||
use Model\Setting;
|
||||
use Modules\Common\Model\Module;
|
||||
@@ -51,7 +52,8 @@ class BaseService
|
||||
public $calculationHooks = array();
|
||||
public $customFieldManager = null;
|
||||
public $migrationManager = null;
|
||||
public $modelClassMap = array();
|
||||
public $modelClassMap = [];
|
||||
public $customFieldsClassMap = [];
|
||||
public $currentProfileId = false;
|
||||
|
||||
protected $cacheService = null;
|
||||
@@ -167,6 +169,20 @@ class BaseService
|
||||
$this->modelClassMap[$modelClass] = $fullQualifiedName;
|
||||
}
|
||||
|
||||
public function getCustomFieldClassMap()
|
||||
{
|
||||
$map = [];
|
||||
foreach($this->customFieldsClassMap as $key => $val) {
|
||||
$map[] = [$key, $val];
|
||||
}
|
||||
return $map;
|
||||
}
|
||||
|
||||
public function addCustomFieldClass($customFieldsClass, $objectName)
|
||||
{
|
||||
$this->customFieldsClassMap[$customFieldsClass] = $objectName;
|
||||
}
|
||||
|
||||
public function getModelClassName($name)
|
||||
{
|
||||
return $this->getFullQualifiedModelClassName($name);
|
||||
@@ -637,7 +653,10 @@ class BaseService
|
||||
|
||||
$processedList = array();
|
||||
foreach ($list as $obj) {
|
||||
$processedList[] = $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
||||
$processedObj = $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
||||
if (null !== $processedObj) {
|
||||
$processedList[] = $processedObj;
|
||||
}
|
||||
}
|
||||
|
||||
$list = $processedList;
|
||||
@@ -749,7 +768,7 @@ class BaseService
|
||||
$obj = $this->enrichObjectCustomFields($table, $obj);
|
||||
|
||||
$obj = $obj->postProcessGetElement($obj);
|
||||
return $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
||||
return $this->cleanUpAdoDB($obj);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -928,6 +947,7 @@ class BaseService
|
||||
{
|
||||
$fileFields = $this->fileFields;
|
||||
$nsTable = $this->getFullQualifiedModelClassName($table);
|
||||
/** @var BaseModel $ele */
|
||||
$ele = new $nsTable();
|
||||
|
||||
$ele->Load('id = ?', array($id));
|
||||
@@ -985,7 +1005,7 @@ class BaseService
|
||||
$dataEntryBackup->data = json_encode($newObj);
|
||||
$dataEntryBackup->Save();
|
||||
}
|
||||
|
||||
$ele->executePostDeleteActions($ele);
|
||||
$this->audit(IceConstants::AUDIT_DELETE, "Deleted an object in ".$table." [id:".$ele->id."]");
|
||||
}
|
||||
|
||||
@@ -998,6 +1018,7 @@ class BaseService
|
||||
}
|
||||
|
||||
$cfs = $this->customFieldManager->getCustomFields($table, $id);
|
||||
/** @var CustomField $cf */
|
||||
foreach ($cfs as $cf) {
|
||||
$cf->Delete();
|
||||
}
|
||||
@@ -1804,7 +1825,7 @@ END;
|
||||
$companyStructure->Load('id = ?', array($parentCompanyStructure));
|
||||
}
|
||||
} while (!empty($companyStructure->id)
|
||||
&& !empty($parentCompanyStructure)
|
||||
&& !empty($parentCompanyStructure)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ class DomainAwareInputCleaner
|
||||
|
||||
$filterData = json_decode($filters, true);
|
||||
foreach ($filterData as $name => $value) {
|
||||
|
||||
if (!$this->isValidColumnName($name) || !$this->isValidFilterValue($value)) {
|
||||
return '';
|
||||
}
|
||||
@@ -90,6 +91,14 @@ class DomainAwareInputCleaner
|
||||
|
||||
private function isValidFilterValue($input)
|
||||
{
|
||||
if (is_array($input)) {
|
||||
$isValid = true;
|
||||
foreach ($input as $val) {
|
||||
$isValid = $isValid && !!preg_match('/^[-_: \d\p{L}]+$/u', $val);
|
||||
}
|
||||
|
||||
return $isValid;
|
||||
}
|
||||
return !!preg_match('/^[-_: \d\p{L}]+$/u', $input);
|
||||
}
|
||||
}
|
||||
|
||||
146
core/src/Classes/ExtensionManager.php
Normal file
146
core/src/Classes/ExtensionManager.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Classes;
|
||||
|
||||
use Utils\LogManager;
|
||||
|
||||
class ExtensionManager
|
||||
{
|
||||
const GROUP = 'extension';
|
||||
protected function processExtensionInDB()
|
||||
{
|
||||
$dbModule = new \Modules\Common\Model\Module();
|
||||
$extensions = $dbModule->Find("mod_group = ?", array(self::GROUP));
|
||||
|
||||
$extensionsInDB = [];
|
||||
foreach ($extensions as $dbm) {
|
||||
$extensionsInDB[$dbm->name] = $dbm;
|
||||
ModuleAccessService::getInstance()->setModule($dbm->name, self::GROUP, $dbm);
|
||||
}
|
||||
|
||||
return $extensionsInDB;
|
||||
}
|
||||
|
||||
public function getExtensionsPath()
|
||||
{
|
||||
return APP_BASE_PATH.'../extensions/';
|
||||
}
|
||||
|
||||
public function getExtensionMetaData($extensionName)
|
||||
{
|
||||
return json_decode(file_get_contents($this->getExtensionsPath().$extensionName.'/meta.json'));
|
||||
}
|
||||
|
||||
public function setupExtensions()
|
||||
{
|
||||
$menu = [];
|
||||
$extensions = [];
|
||||
$extensionDirs = scandir($this->getExtensionsPath());
|
||||
$currentLocation = 0;
|
||||
|
||||
$extensionsInDB = $this->processExtensionInDB();
|
||||
|
||||
$needToInstall = false;
|
||||
|
||||
foreach ($extensionDirs as $extensionDir) {
|
||||
if (is_dir($this->getExtensionsPath().$extensionDir) && $extensionDir != '.' && $extensionDir != '..') {
|
||||
$meta = $this->getExtensionMetaData($extensionDir);
|
||||
|
||||
$arr = [];
|
||||
$arr['name'] = $extensionDir;
|
||||
$arr['label'] = $meta->label;
|
||||
$arr['icon'] = $meta->icon;
|
||||
$arr['menu'] = $meta->menu[0];
|
||||
$arr['order'] = 0;
|
||||
$arr['status'] = 'Enabled';
|
||||
$arr['user_levels'] = $meta->user_levels;
|
||||
$arr['user_roles'] = isset($meta->user_roles)?$meta->user_roles:"";
|
||||
$arr['model_namespace'] = $meta->model_namespace;
|
||||
$arr['manager'] = $meta->manager;
|
||||
|
||||
// Add menu
|
||||
$menu[$meta->menu[0]] = $meta->menu[1];
|
||||
|
||||
//Check in admin dbmodules
|
||||
if (isset($extensionsInDB[$arr['name']])) {
|
||||
$dbModule = $extensionsInDB[$arr['name']];
|
||||
|
||||
$arr['name'] = $dbModule->name;
|
||||
$arr['label'] = $dbModule->label;
|
||||
$arr['icon'] = $dbModule->icon;
|
||||
$arr['menu'] = $dbModule->menu;
|
||||
$arr['status'] = $dbModule->status;
|
||||
$arr['user_levels'] = json_decode($dbModule->user_levels);
|
||||
$arr['user_roles'] = empty($dbModule->user_roles)
|
||||
? [] : json_decode($dbModule->user_roles);
|
||||
$arr['user_roles_blacklist'] = empty($dbModule->user_roles_blacklist)
|
||||
? [] : json_decode($dbModule->user_roles_blacklist);
|
||||
} else {
|
||||
$dbModule = new \Modules\Common\Model\Module();
|
||||
$dbModule->menu = $arr['menu'];
|
||||
$dbModule->name = $arr['name'];
|
||||
$dbModule->label = $arr['label'];
|
||||
$dbModule->icon = $arr['icon'];
|
||||
$dbModule->mod_group = self::GROUP;
|
||||
$dbModule->mod_order = $arr['order'];
|
||||
$dbModule->status = "Enabled";
|
||||
$dbModule->version = isset($meta->version)?$meta->version:"";
|
||||
$dbModule->update_path = self::GROUP.">".$extensionDir;
|
||||
$dbModule->user_levels = isset($meta->user_levels)?json_encode($meta->user_levels):"";
|
||||
$dbModule->user_roles = isset($meta->user_roles)?json_encode($meta->user_roles):"";
|
||||
|
||||
$ok = $dbModule->Save();
|
||||
if (!$ok) {
|
||||
LogManager::getInstance()->error('Error saving module: '.$dbModule->name);
|
||||
}
|
||||
$needToInstall = $ok;
|
||||
}
|
||||
|
||||
/* @var \Classes\AbstractModuleManager */
|
||||
$manager = $this->includeModuleManager($extensionDir, $arr);
|
||||
if ($dbModule->status == 'Disabled') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($needToInstall) {
|
||||
$manager->install();
|
||||
}
|
||||
|
||||
$menuName = $arr['menu'];
|
||||
if (!isset($extensions[$menuName])) {
|
||||
$extensions[$menuName] = array();
|
||||
}
|
||||
|
||||
if (!$meta->headless) {
|
||||
if ($arr['order'] == '0' || $arr['order'] == '') {
|
||||
$extensions[$menuName]["Z".$currentLocation] = $arr;
|
||||
$currentLocation++;
|
||||
} else {
|
||||
$extensions[$arr['menu']]["A".$arr['order']] = $arr;
|
||||
}
|
||||
}
|
||||
|
||||
$initializer = $manager->getInitializer();
|
||||
if ($initializer !== null) {
|
||||
$initializer->setBaseService(BaseService::getInstance());
|
||||
$initializer->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$menu, $extensions];
|
||||
}
|
||||
|
||||
public function includeModuleManager($name, $data)
|
||||
{
|
||||
include($this->getExtensionsPath().$name.'/'.$name.'.php');
|
||||
$moduleManagerClass = $data['manager'];
|
||||
/* @var \Classes\AbstractModuleManager $moduleManagerObj*/
|
||||
$moduleManagerObj = new $moduleManagerClass();
|
||||
$moduleManagerObj->setModuleObject($data);
|
||||
$moduleManagerObj->setModuleType(self::GROUP);
|
||||
$moduleManagerObj->setModulePath(CLIENT_PATH.'/'.self::GROUP.'/'.$name);
|
||||
\Classes\BaseService::getInstance()->addModuleManager($moduleManagerObj);
|
||||
return $moduleManagerObj;
|
||||
}
|
||||
}
|
||||
20
core/src/Classes/IceExtension.php
Normal file
20
core/src/Classes/IceExtension.php
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
namespace Classes;
|
||||
|
||||
abstract class IceExtension extends AbstractModuleManager
|
||||
{
|
||||
public function initializeUserClasses()
|
||||
{
|
||||
// TODO: Implement initializeUserClasses() method.
|
||||
}
|
||||
|
||||
public function initializeFieldMappings()
|
||||
{
|
||||
// TODO: Implement initializeFieldMappings() method.
|
||||
}
|
||||
|
||||
public function initializeDatabaseErrorMappings()
|
||||
{
|
||||
// TODO: Implement initializeDatabaseErrorMappings() method.
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Classes;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\SignatureInvalidException;
|
||||
|
||||
class JwtTokenService
|
||||
{
|
||||
@@ -22,7 +23,11 @@ class JwtTokenService
|
||||
public function getBaseToken($jwtToken)
|
||||
{
|
||||
$secret = APP_SEC.APP_PASSWORD;
|
||||
$jwt = JWT::decode($jwtToken, $secret, array('HS256'));
|
||||
try {
|
||||
$jwt = JWT::decode($jwtToken, $secret, array('HS256'));
|
||||
} catch (SignatureInvalidException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (time() > intval($jwt->expire)) {
|
||||
return null;
|
||||
|
||||
@@ -15,6 +15,8 @@ class MemcacheService
|
||||
public static $openConnections = array();
|
||||
private static $me = null;
|
||||
|
||||
protected $inMemoryStore = [];
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
}
|
||||
@@ -56,6 +58,15 @@ class MemcacheService
|
||||
}
|
||||
|
||||
public function set($key, $value, $expiry = 3600)
|
||||
{
|
||||
if (!$this->setInServer($key, $value, $expiry)) {
|
||||
$this->inMemoryStore[$this->compressKey($key)] = $value;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function setInServer($key, $value, $expiry = 3600)
|
||||
{
|
||||
if (!class_exists('\\Memcached')) {
|
||||
return false;
|
||||
@@ -74,6 +85,19 @@ class MemcacheService
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
$data = $this->getFromServer($key);
|
||||
if ($data) {
|
||||
return $data;
|
||||
}
|
||||
if (isset($this->inMemoryStore[$this->compressKey($key)])) {
|
||||
return $this->inMemoryStore[$this->compressKey($key)];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getFromServer($key)
|
||||
{
|
||||
if (!class_exists('\\Memcached')) {
|
||||
return false;
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
|
||||
namespace Classes\Migration;
|
||||
|
||||
use Utils\LogManager;
|
||||
|
||||
abstract class AbstractMigration
|
||||
{
|
||||
protected $file;
|
||||
@@ -16,7 +18,7 @@ abstract class AbstractMigration
|
||||
|
||||
protected $lastError;
|
||||
|
||||
public function __construct($file)
|
||||
public function __construct($file = null)
|
||||
{
|
||||
$this->file = $file;
|
||||
}
|
||||
@@ -50,6 +52,7 @@ abstract class AbstractMigration
|
||||
$ret = $this->db()->Execute($sql);
|
||||
if (!$ret) {
|
||||
$this->lastError = $this->db()->ErrorMsg();
|
||||
LogManager::getInstance()->error('Error in migration: '.$this->lastError);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class ModuleAccess
|
||||
* @param $name
|
||||
* @param $group
|
||||
*/
|
||||
public function __construct($name, $group)
|
||||
public function __construct($name, $group = 'extension')
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->group = $group;
|
||||
|
||||
98
core/src/Classes/ModuleBuilderV2/ModuleBuilder.php
Normal file
98
core/src/Classes/ModuleBuilderV2/ModuleBuilder.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Thilina
|
||||
* Date: 8/20/17
|
||||
* Time: 9:47 AM
|
||||
*/
|
||||
|
||||
namespace Classes\ModuleBuilderV2;
|
||||
|
||||
use Classes\PermissionManager;
|
||||
|
||||
class ModuleBuilder
|
||||
{
|
||||
public $modules = array();
|
||||
public $user = null;
|
||||
|
||||
function __construct()
|
||||
{
|
||||
$this->user = \Classes\BaseService::getInstance()->getCurrentUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ModuleTab $module
|
||||
*/
|
||||
public function addModuleOrGroup($module)
|
||||
{
|
||||
$this->modules[] = $module;
|
||||
}
|
||||
|
||||
public function getTabHeadersHTML()
|
||||
{
|
||||
$html = "";
|
||||
foreach ($this->modules as $module) {
|
||||
$html .= $module->getHTML()."\r\n";
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function getTabPagesHTML()
|
||||
{
|
||||
$html = "";
|
||||
/* @var ModuleTab $module */
|
||||
foreach ($this->modules as $module) {
|
||||
if (get_class($module) === ModuleTab::class) {
|
||||
$html .= $module->getPageHTML()."\r\n";
|
||||
} else {
|
||||
/* @var ModuleTab $mod */
|
||||
foreach ($module->modules as $mod) {
|
||||
$html .= $mod->getPageHTML()."\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function getModJsHTML()
|
||||
{
|
||||
$moduleData = [
|
||||
'user_level' => $this->user->user_level,
|
||||
'permissions' => [
|
||||
]
|
||||
];
|
||||
|
||||
$html = "var modJsList = new Array();\r\n";
|
||||
$activeModule = "";
|
||||
/* @var ModuleTab $module */
|
||||
foreach ($this->modules as $module) {
|
||||
if (get_class($module) == ModuleTab::class) {
|
||||
$html .= $module->getJSObjectCode()."\r\n";
|
||||
|
||||
$modelClass = $module->modelPath;
|
||||
$moduleData['permissions'][$module->name] = PermissionManager::checkGeneralAccess(new $modelClass());
|
||||
|
||||
if ($module->isActive) {
|
||||
$activeModule = $module->name;
|
||||
}
|
||||
} else {
|
||||
/* @var ModuleTab $mod */
|
||||
foreach ($module->modules as $mod) {
|
||||
$modelClass = $mod->modelPath;
|
||||
$moduleData['permissions'][$mod->name] = PermissionManager::checkGeneralAccess(new $modelClass());
|
||||
|
||||
if ($module->isActive && $activeModule == "") {
|
||||
$activeModule = $mod->name;
|
||||
}
|
||||
$html .= $mod->getJSObjectCode()."\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$html .= "var modJs = modJsList['tab".$activeModule."'];\r\n";
|
||||
|
||||
$html = "var data = ".json_encode($moduleData).";\r\n".$html;
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
96
core/src/Classes/ModuleBuilderV2/ModuleTab.php
Normal file
96
core/src/Classes/ModuleBuilderV2/ModuleTab.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Thilina
|
||||
* Date: 8/20/17
|
||||
* Time: 9:47 AM
|
||||
*/
|
||||
|
||||
namespace Classes\ModuleBuilderV2;
|
||||
|
||||
class ModuleTab
|
||||
{
|
||||
public $modelPath;
|
||||
public $name;
|
||||
public $class;
|
||||
public $label;
|
||||
public $adapterName;
|
||||
public $filter;
|
||||
public $orderBy;
|
||||
public $isActive = false;
|
||||
public $isInsideGroup = false;
|
||||
public $options = array();
|
||||
|
||||
public function __construct(
|
||||
$modelPath,
|
||||
$name,
|
||||
$class,
|
||||
$label,
|
||||
$adapterName,
|
||||
$filter,
|
||||
$orderBy,
|
||||
$isActive = false,
|
||||
$options = array()
|
||||
)
|
||||
{
|
||||
$this->modelPath = $modelPath;
|
||||
$this->name = $name;
|
||||
$this->class = $class;
|
||||
$this->label = $label;
|
||||
$this->adapterName = $adapterName;
|
||||
$this->filter = $filter;
|
||||
$this->orderBy = $orderBy;
|
||||
$this->isActive = $isActive;
|
||||
|
||||
$this->options = array_merge(
|
||||
$options, [
|
||||
"setObjectTypeName" => "'{$this->name}'",
|
||||
"setAccess" => "data.permissions.{$this->name} ? data.permissions.{$this->name} : {}",
|
||||
"setDataPipe" => 'new IceDataPipe(modJsList.tab' . $this->name . ')',
|
||||
"setRemoteTable" => true,
|
||||
]);
|
||||
}
|
||||
|
||||
public function getHTML()
|
||||
{
|
||||
$active = ($this->isActive)?"active":"";
|
||||
if (!$this->isInsideGroup) {
|
||||
return '<li class="' . $active . '"><a id="tab' . $this->name
|
||||
. '" href="#tabPage' . $this->name . '">' . t($this->label) . '</a></li>';
|
||||
} else {
|
||||
return '<li class="' . $active . '"><a id="tab' . $this->name
|
||||
. '" href="#tabPage' . $this->name . '">' . t($this->label) . '</a></li>';
|
||||
}
|
||||
}
|
||||
|
||||
public function getPageHTML()
|
||||
{
|
||||
$active = ($this->isActive)?" active":"";
|
||||
$html = '<div class="tab-pane'.$active.'" id="tabPage'.$this->name.'">'.
|
||||
'<div id="'.$this->name.'Table" class="reviewBlock" data-content="List" style="padding-left:5px;"></div>'.
|
||||
'<div id="'.$this->name.'Form"></div>'.
|
||||
'<div id="'.$this->name.'FilterForm"></div>'.
|
||||
'</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function getJSObjectCode()
|
||||
{
|
||||
$js = "";
|
||||
if (empty($this->filter)) {
|
||||
$js.= "modJsList['tab" . $this->name . "'] = new " .
|
||||
$this->adapterName . "('" . $this->class . "','" . $this->name . "','','".$this->orderBy. "');\r\n";
|
||||
} else {
|
||||
$js.= "modJsList['tab" . $this->name . "'] = new " .
|
||||
$this->adapterName . "('" . $this->class . "','" . $this->name . "'," .
|
||||
$this->filter . ",'".$this->orderBy. "');\r\n";
|
||||
}
|
||||
|
||||
foreach ($this->options as $key => $val) {
|
||||
$js.= "modJsList['tab" . $this->name . "'].".$key."(".$val. ");\r\n";
|
||||
}
|
||||
|
||||
return $js;
|
||||
}
|
||||
}
|
||||
53
core/src/Classes/ModuleBuilderV2/ModuleTabGroup.php
Normal file
53
core/src/Classes/ModuleBuilderV2/ModuleTabGroup.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Thilina
|
||||
* Date: 8/20/17
|
||||
* Time: 9:48 AM
|
||||
*/
|
||||
|
||||
namespace Classes\ModuleBuilderV2;
|
||||
|
||||
class ModuleTabGroup
|
||||
{
|
||||
public $name;
|
||||
public $label;
|
||||
public $isActive = false;
|
||||
public $modules = array();
|
||||
|
||||
public function __construct($name, $label)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->label = $label;
|
||||
}
|
||||
|
||||
public function addModuleTab($moduleTab)
|
||||
{
|
||||
if ($moduleTab->isActive) {
|
||||
$this->isActive = true;
|
||||
$moduleTab->isActive = false;
|
||||
}
|
||||
$moduleTab->isInsideGroup = true;
|
||||
$this->modules[] = $moduleTab;
|
||||
}
|
||||
|
||||
public function getHTML()
|
||||
{
|
||||
$html = "";
|
||||
$active = ($this->isActive)?" active":"";
|
||||
|
||||
$html.= '<li class="dropdown'.$active.'">'."\r\n".
|
||||
'<a href="#" id="'.$this->name.
|
||||
'" class="dropdown-toggle" data-toggle="dropdown" aria-controls="'.$this->name.
|
||||
'-contents">'.$this->label.' <span class="caret"></span></a>'."\r\n".
|
||||
'<ul class="dropdown-menu" role="menu" aria-labelledby="'.$this->name.'" id="'.$this->name.'-contents">';
|
||||
|
||||
foreach ($this->modules as $module) {
|
||||
$html.= $module->getHTML();
|
||||
}
|
||||
|
||||
$html .= "</ul></li>";
|
||||
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
@@ -103,7 +103,7 @@ class PasswordManager
|
||||
return new IceResponse(IceResponse::ERROR, $error);
|
||||
}
|
||||
|
||||
if (strlen($password) > 20) {
|
||||
if (strlen($password) > 30) {
|
||||
$error = "Password too long";
|
||||
|
||||
return new IceResponse(IceResponse::ERROR, $error);
|
||||
|
||||
@@ -424,10 +424,8 @@ class RestEndPoint
|
||||
$token = $_GET['token'];
|
||||
}
|
||||
|
||||
if (strlen($token) > 32) {
|
||||
$tokenService = new JwtTokenService();
|
||||
$token = $tokenService->getBaseToken($token);
|
||||
}
|
||||
$tokenService = new JwtTokenService();
|
||||
$token = $tokenService->getBaseToken($token);
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
85
core/src/Classes/SAMLManager.php
Normal file
85
core/src/Classes/SAMLManager.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace Classes;
|
||||
|
||||
use \RobRichards\XMLSecLibs\MoXMLSecurityKey;
|
||||
use Utils\LogManager;
|
||||
|
||||
class SAMLManager
|
||||
{
|
||||
public function getSSOEmail($samlData, $relayState) {
|
||||
// Service Providers Assertion Consumer Service (ACS) URL
|
||||
$acsUrl = CLIENT_BASE_URL.'login.php';
|
||||
$samlResponse = htmlspecialchars($samlData);
|
||||
|
||||
$samlResponse = base64_decode($samlResponse);
|
||||
|
||||
$document = new \DOMDocument();
|
||||
$document->loadXML($samlResponse);
|
||||
$samlResponseXml = $document->firstChild;
|
||||
|
||||
$doc = $document->documentElement;
|
||||
$xpath = new \DOMXpath($document);
|
||||
$xpath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
|
||||
$xpath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
|
||||
|
||||
$status = $xpath->query('/samlp:Response/samlp:Status/samlp:StatusCode', $doc);
|
||||
$statusString = $status->item(0)->getAttribute('Value');
|
||||
|
||||
|
||||
$statusArray = explode(':',$statusString);
|
||||
if(array_key_exists(7, $statusArray)){
|
||||
$status = $statusArray[7];
|
||||
}
|
||||
|
||||
if ('Success' !== $status) {
|
||||
$StatusMessage = $xpath->query('/samlp:Response/samlp:Status/samlp:StatusMessage', $doc)->item(0);
|
||||
LogManager::getInstance()->error('SAML login failed: status = '. $status);
|
||||
if(!empty($StatusMessage)) {
|
||||
$StatusMessage = $StatusMessage->nodeValue;
|
||||
LogManager::getInstance()->error('SAML login failed: status message = '. $StatusMessage);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
$x509cert = SettingsManager::getInstance()->getSetting('SAML: X.509 Certificate');
|
||||
|
||||
$samlResponse = new \SAML2_Response($samlResponseXml);
|
||||
$responseSignatureData = $samlResponse->getSignatureData();
|
||||
$assertionSignatureData = current($samlResponse->getAssertions())->getSignatureData();
|
||||
|
||||
$certFingerPrint = MoXMLSecurityKey::getRawThumbprint($x509cert);
|
||||
$certFingerPrint = preg_replace('/\s+/', '', $certFingerPrint);
|
||||
$validSignature = false;
|
||||
if(!empty($responseSignatureData)) {
|
||||
$validSignature = \Utilities::processResponse($acsUrl, $certFingerPrint, $responseSignatureData, $samlResponse, 0, $relayState);
|
||||
LogManager::getInstance()->error('SAML: response signature validity :'.$validSignature);
|
||||
}
|
||||
|
||||
if(!empty($assertionSignatureData)) {
|
||||
$validSignature = \Utilities::processResponse($acsUrl, $certFingerPrint, $assertionSignatureData, $samlResponse, 0, $relayState);
|
||||
LogManager::getInstance()->error('SAML: response signature validity :'.$validSignature);
|
||||
}
|
||||
|
||||
if(!$validSignature) {
|
||||
LogManager::getInstance()->error('Invalid response or assertion signature');
|
||||
return false;
|
||||
}
|
||||
|
||||
$issuer = current($samlResponse->getAssertions())->getIssuer();
|
||||
$assertion = current($samlResponse->getAssertions());
|
||||
$audiences = $assertion->getValidAudiences();
|
||||
$expectedIssuer = SettingsManager::getInstance()->getSetting('SAML: IDP Issuer');
|
||||
if ($issuer !== $expectedIssuer) {
|
||||
LogManager::getInstance()->error('SAML Invalid Issuer :'.$issuer.' expected :'.$expectedIssuer);
|
||||
return false;
|
||||
}
|
||||
|
||||
$ssoEmail = current(current($samlResponse->getAssertions())->getNameId());
|
||||
if (!$ssoEmail) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $ssoEmail;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,22 @@
|
||||
<?php
|
||||
namespace Classes;
|
||||
|
||||
use Classes\Crypt\AesCtr;
|
||||
use Model\Setting;
|
||||
|
||||
class SettingsManager
|
||||
{
|
||||
|
||||
const ENCRYPTED_PREFIX = 'iceenc_';
|
||||
|
||||
private static $me = null;
|
||||
|
||||
private $encryptedSettings = [];
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->addEncryptedSetting('SAML: X.509 Certificate');
|
||||
$this->addEncryptedSetting('LDAP: Manager Password');
|
||||
}
|
||||
|
||||
public static function getInstance()
|
||||
@@ -21,9 +28,62 @@ class SettingsManager
|
||||
return self::$me;
|
||||
}
|
||||
|
||||
public function addEncryptedSetting($name) {
|
||||
if (!$this->isEncryptedSetting($name)) {
|
||||
$this->encryptedSettings[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
public function isEncryptedSetting($name) {
|
||||
return in_array($name, $this->encryptedSettings);
|
||||
}
|
||||
|
||||
public function getInstanceKey() {
|
||||
$settings = new Setting();
|
||||
$settings->Load("name = ?", array("Instance: Key"));
|
||||
if ($settings->name != "Instance: Key") {
|
||||
return null;
|
||||
}
|
||||
return $settings->value;
|
||||
}
|
||||
|
||||
private function encrypt($value) {
|
||||
$id = BaseService::getInstance()->getInstanceId();
|
||||
$key = $this->getInstanceKey();
|
||||
return AesCtr::encrypt($value, $id.$key, 256);
|
||||
}
|
||||
|
||||
public function encryptSetting($name, $value) {
|
||||
// check the existence of prefix and encrypt only if need to avoid double encryption
|
||||
if (
|
||||
$this->isEncryptedSetting($name)
|
||||
&& substr($value, 0, strlen(self::ENCRYPTED_PREFIX)) !== self::ENCRYPTED_PREFIX
|
||||
) {
|
||||
$value = self::ENCRYPTED_PREFIX.$this->encrypt($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
private function decrypt($value) {
|
||||
$id = BaseService::getInstance()->getInstanceId();
|
||||
$key = $this->getInstanceKey();
|
||||
return AesCtr::decrypt($value, $id.$key, 256);
|
||||
}
|
||||
|
||||
public function decryptSetting($name, $value) {
|
||||
if (
|
||||
$this->isEncryptedSetting($name)
|
||||
&& substr($value, 0, strlen(self::ENCRYPTED_PREFIX)) === self::ENCRYPTED_PREFIX
|
||||
) {
|
||||
$value = $this->decrypt(substr($value, strlen(self::ENCRYPTED_PREFIX)));
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getSetting($name)
|
||||
{
|
||||
|
||||
if (class_exists("\\Classes\\ProVersion")) {
|
||||
$pro = new ProVersion();
|
||||
$val = $pro->getSetting($name);
|
||||
@@ -34,20 +94,28 @@ class SettingsManager
|
||||
|
||||
$setting = new Setting();
|
||||
$setting->Load("name = ?", array($name));
|
||||
$value = null;
|
||||
if ($setting->name == $name) {
|
||||
return $setting->value;
|
||||
$value = $setting->value;
|
||||
}
|
||||
return null;
|
||||
|
||||
if (null === $value) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->decryptSetting($name, $value);
|
||||
}
|
||||
|
||||
public function setSetting($name, $value)
|
||||
{
|
||||
$setting = new Setting();
|
||||
$setting->Load("name = ?", array($name));
|
||||
if ($setting->name == $name) {
|
||||
$setting->value = $value;
|
||||
$setting->Save();
|
||||
if ($setting->name !== $name) {
|
||||
return;
|
||||
}
|
||||
|
||||
$setting->value = $this->encryptSetting($name, $value);
|
||||
$setting->Save();
|
||||
}
|
||||
|
||||
public function addSetting($name, $value)
|
||||
@@ -55,14 +123,21 @@ class SettingsManager
|
||||
$setting = new Setting();
|
||||
$setting->Load("name = ?", array($name));
|
||||
if ($setting->name == $name) {
|
||||
$setting->value = $value;
|
||||
$setting->value = $this->encryptSetting($name, $value);
|
||||
$setting->Save();
|
||||
} else {
|
||||
$setting->name = $name;
|
||||
$setting->value = $value;
|
||||
$setting->description = $value;
|
||||
$setting->value = $this->encryptSetting($name, $value);
|
||||
$setting->description = '';
|
||||
$setting->meta = '';
|
||||
$setting->Save();
|
||||
}
|
||||
}
|
||||
|
||||
public function getDeprecatedSettings() {
|
||||
return [
|
||||
'Attendance: Work Week Start Day',
|
||||
'Attendance: Overtime Calculation Class'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,9 +5,14 @@ use Classes\IceResponse;
|
||||
use Classes\ModuleAccess;
|
||||
use Employees\Common\Model\Employee;
|
||||
use Model\BaseModel;
|
||||
use Model\CustomFieldTrait;
|
||||
|
||||
class CompanyStructure extends BaseModel
|
||||
{
|
||||
use CustomFieldTrait;
|
||||
public $objectName = 'Company Structures';
|
||||
protected $allowCustomFields = true;
|
||||
|
||||
public $table = 'CompanyStructures';
|
||||
|
||||
public function getAdminAccess()
|
||||
|
||||
25
core/src/CustomField/Admin/Api/CustomFieldAdminManager.php
Normal file
25
core/src/CustomField/Admin/Api/CustomFieldAdminManager.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace CustomField\Admin\Api;
|
||||
|
||||
use Classes\AbstractModuleManager;
|
||||
|
||||
class CustomFieldAdminManager extends AbstractModuleManager
|
||||
{
|
||||
public function initializeUserClasses()
|
||||
{
|
||||
}
|
||||
|
||||
public function initializeFieldMappings()
|
||||
{
|
||||
}
|
||||
|
||||
public function initializeDatabaseErrorMappings()
|
||||
{
|
||||
}
|
||||
|
||||
public function setupModuleClassDefinitions()
|
||||
{
|
||||
$this->addModelClass('CustomField');
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,11 @@ class DocumentTaskCreator implements TaskCreator
|
||||
return 0;
|
||||
}
|
||||
|
||||
$query = "select count(id) as c from EmployeeDocuments where employee = ? and valid_until < ?";
|
||||
$query = "select count(id) as c from EmployeeDocuments where employee = ? and valid_until < ? and visible_to = ?";
|
||||
|
||||
$user->DB()->SetFetchMode(ADODB_FETCH_ASSOC);
|
||||
$rs = $user->DB()->Execute($query, [$employee->id, date('Y-m-d')]);
|
||||
// TODO - sending notifications only for Owner documents, this need to be extended later
|
||||
$rs = $user->DB()->Execute($query, [$employee->id, date('Y-m-d'), 'Owner']);
|
||||
$count = $rs->fields['c'];
|
||||
|
||||
return $count;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Documents\Common\Model;
|
||||
|
||||
use Classes\BaseService;
|
||||
use Classes\ModuleAccess;
|
||||
use Model\BaseModel;
|
||||
|
||||
@@ -26,4 +27,23 @@ class Document extends BaseModel
|
||||
new ModuleAccess('documents', 'user'),
|
||||
];
|
||||
}
|
||||
|
||||
public function fieldValueMethods()
|
||||
{
|
||||
return ['getDocumentTypesForUser'];
|
||||
}
|
||||
|
||||
public function getDocumentTypesForUser()
|
||||
{
|
||||
$documents = new Document();
|
||||
if (BaseService::getInstance()->currentUser->user_level === 'Employee'
|
||||
|| BaseService::getInstance()->currentUser->user_level === 'Restricted Employee'
|
||||
) {
|
||||
$documents = $documents->Find('share_with_employee = ?', ['Yes']);
|
||||
} else {
|
||||
$documents = $documents->Find('1 = 1');
|
||||
}
|
||||
|
||||
return $documents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,65 @@
|
||||
|
||||
namespace Documents\Common\Model;
|
||||
|
||||
use Classes\BaseService;
|
||||
use Classes\IceResponse;
|
||||
use Classes\ModuleAccess;
|
||||
use Employees\Common\Model\Employee;
|
||||
use Model\BaseModel;
|
||||
|
||||
class EmployeeDocument extends BaseModel
|
||||
{
|
||||
public $table = 'EmployeeDocuments';
|
||||
|
||||
private function getHiddenDocumentTypeIds()
|
||||
{
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
|
||||
{
|
||||
$find = '';
|
||||
$user = BaseService::getInstance()->getCurrentUser();
|
||||
|
||||
if ($user->user_level == 'Employee') {
|
||||
$find = ' visible_to = \'Owner\' AND ';
|
||||
$document = new Document();
|
||||
$hiddenDocumentTypes = $document->Find(
|
||||
"share_with_employee = ?",
|
||||
['No']
|
||||
);
|
||||
|
||||
$hiddenTypeIds = [];
|
||||
foreach ($hiddenDocumentTypes as $hiddenDocumentType) {
|
||||
$hiddenTypeIds[] = $hiddenDocumentType->id;
|
||||
}
|
||||
|
||||
if(count($hiddenTypeIds) > 0) {
|
||||
$find .= ' document NOT IN (\''.implode('\',\'', $hiddenTypeIds).'\') AND ';
|
||||
}
|
||||
|
||||
return parent::Find($find.$whereOrderBy, $bindarr, $pkeysArr, $extra);
|
||||
|
||||
} else if ($user->user_level == 'Manager') {
|
||||
// Original $whereOrderBy already contain employee selection
|
||||
// So here if isSubOrdinates is true if the query coming from Employee -> Document Management
|
||||
// In that case we need to show documents from sub ordinates
|
||||
// These docs can can be owner and manager both
|
||||
if (isset($isSubOrdinates) && $isSubOrdinates) {
|
||||
$find .= ' visible_to in (\'Owner\', \'Manager\') AND ';
|
||||
} else {
|
||||
// Here we are showing the documents for the manager
|
||||
// If someone upload a document for this manager and make it visible to manager,
|
||||
// that means only the manager of this manager can see the document
|
||||
// So it should not be visible to this manager
|
||||
$find .= ' visible_to in (\'Owner\') AND ';
|
||||
}
|
||||
}
|
||||
|
||||
return parent::Find($find.$whereOrderBy, $bindarr, $pkeysArr, $extra);
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
public function getAdminAccess()
|
||||
{
|
||||
return array("get","element","save","delete");
|
||||
@@ -26,6 +77,8 @@ class EmployeeDocument extends BaseModel
|
||||
return array("get","element","save","delete");
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getUserAccess()
|
||||
{
|
||||
return array("get");
|
||||
|
||||
@@ -8,6 +8,7 @@ use Classes\ModuleAccess;
|
||||
use Company\Common\Model\CompanyStructure;
|
||||
use Metadata\Common\Model\Country;
|
||||
use Model\BaseModel;
|
||||
use Model\CustomFieldTrait;
|
||||
|
||||
class Employee extends BaseModel
|
||||
{
|
||||
@@ -90,6 +91,11 @@ class Employee extends BaseModel
|
||||
$this->oldObj = BaseService::getInstance()->getElement('Employee', $obj->id, $mapping, true);
|
||||
}
|
||||
|
||||
public function isCustomFieldsEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private function saveHistory($obj)
|
||||
{
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use Classes\BaseService;
|
||||
use Classes\IceResponse;
|
||||
use Classes\ModuleAccess;
|
||||
use Model\BaseModel;
|
||||
use Utils\LogManager;
|
||||
|
||||
class CustomField extends BaseModel
|
||||
{
|
||||
@@ -58,6 +59,22 @@ class CustomField extends BaseModel
|
||||
return new IceResponse(IceResponse::SUCCESS, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CustomField $obj
|
||||
*/
|
||||
public function executePostDeleteActions($obj)
|
||||
{
|
||||
$ret = $this->DB()->Execute(
|
||||
'DELETE FROM CustomFieldValues where type = ? and name = ?',
|
||||
[$obj->type, $obj->name]
|
||||
);
|
||||
|
||||
if (!$ret) {
|
||||
$this->lastError = $this->db()->ErrorMsg();
|
||||
LogManager::getInstance()->error('Error deleting custom field values: '.$this->DB()->ErrorMsg());
|
||||
}
|
||||
}
|
||||
|
||||
public function getModuleAccess()
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -11,6 +11,8 @@ use Utils\LogManager;
|
||||
|
||||
class BaseModel extends \ADOdb_Active_Record
|
||||
{
|
||||
public $objectName = null;
|
||||
protected $allowCustomFields = false;
|
||||
|
||||
public $keysToIgnore = array(
|
||||
"_table",
|
||||
@@ -195,6 +197,16 @@ class BaseModel extends \ADOdb_Active_Record
|
||||
{
|
||||
}
|
||||
|
||||
public function executePostDeleteActions($obj)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* If null is returned the object wont be included in the response
|
||||
*
|
||||
* @param $obj
|
||||
* @return mixed
|
||||
*/
|
||||
public function postProcessGetData($obj)
|
||||
{
|
||||
return $obj;
|
||||
@@ -340,4 +352,14 @@ class BaseModel extends \ADOdb_Active_Record
|
||||
return $ok;
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
|
||||
public function getObjectName()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isCustomFieldsEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
16
core/src/Model/CustomFieldTrait.php
Normal file
16
core/src/Model/CustomFieldTrait.php
Normal file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Model;
|
||||
|
||||
trait CustomFieldTrait
|
||||
{
|
||||
public function getObjectName()
|
||||
{
|
||||
return $this->objectName;
|
||||
}
|
||||
|
||||
public function isCustomFieldsEnabled()
|
||||
{
|
||||
return $this->allowCustomFields;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ use Classes\BaseService;
|
||||
use Classes\IceResponse;
|
||||
use Classes\ModuleAccess;
|
||||
use Classes\RestApiManager;
|
||||
use Classes\SettingsManager;
|
||||
use Users\Common\Model\User;
|
||||
|
||||
class Setting extends BaseModel
|
||||
@@ -74,6 +75,12 @@ class Setting extends BaseModel
|
||||
return new IceResponse(IceResponse::SUCCESS, "");
|
||||
}
|
||||
|
||||
public function executePreSaveActions($obj)
|
||||
{
|
||||
$obj->value = SettingsManager::getInstance()->encryptSetting($obj->name, $obj->value);
|
||||
return new IceResponse(IceResponse::SUCCESS, $obj);
|
||||
}
|
||||
|
||||
public function executePreUpdateActions($obj)
|
||||
{
|
||||
return $this->executePreSaveActions($obj);
|
||||
@@ -87,5 +94,17 @@ class Setting extends BaseModel
|
||||
{
|
||||
}
|
||||
|
||||
public function postProcessGetData($obj)
|
||||
{
|
||||
if (in_array($obj->name, SettingsManager::getInstance()->getDeprecatedSettings())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (strlen($obj->value) > 30) {
|
||||
$obj->value = substr($obj->value,0, 30).'...';
|
||||
}
|
||||
return $obj;
|
||||
}
|
||||
|
||||
public $table = 'Settings';
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
namespace Reports\Admin\Reports;
|
||||
|
||||
use Attendance\Common\Model\Attendance;
|
||||
use Company\Common\Model\CompanyStructure;
|
||||
use Employees\Common\Model\Employee;
|
||||
use Reports\Admin\Api\ClassBasedReportBuilder;
|
||||
use Reports\Admin\Api\ReportBuilderInterface;
|
||||
@@ -16,6 +17,18 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
||||
LogManager::getInstance()->info(json_encode($report));
|
||||
LogManager::getInstance()->info(json_encode($req));
|
||||
|
||||
if (
|
||||
empty($req['period'])
|
||||
&& (
|
||||
empty($req['date_start'])
|
||||
|| 'NULL' === $req['date_start']
|
||||
|| empty($req['date_end'])
|
||||
|| 'NULL' === $req['date_end']
|
||||
)
|
||||
) {
|
||||
$req['period'] = 'Current Month';
|
||||
}
|
||||
|
||||
$employeeTimeEntry = new EmployeeTimeEntry();
|
||||
|
||||
$timeEntryList = $employeeTimeEntry->Find(
|
||||
@@ -38,6 +51,8 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
||||
//$minutes = (int)($seconds/60);
|
||||
//Find Attendance Entries
|
||||
|
||||
$req = $this->setRequestDatesBasedOnThePeriod($req);
|
||||
|
||||
$attendance = new Attendance();
|
||||
$atteandanceList = $attendance->Find(
|
||||
"employee = ? and date(in_time) >= ? and date(out_time) <= ? and in_time < out_time",
|
||||
@@ -66,21 +81,34 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
||||
$employeeObject = new Employee();
|
||||
$employeeObject->Load("id = ?", array($req['employee']));
|
||||
|
||||
$company = new CompanyStructure();
|
||||
$company->Load('id = ?', [$employeeObject->department]);
|
||||
|
||||
$reportData = array();
|
||||
//$reportData[] = array($employeeObject->first_name." ".$employeeObject->last_name,"","","","");
|
||||
$reportData[] = array("Date","First Punch-In Time","Last Punch-Out Time","Time in Office","Time in Timesheets");
|
||||
$reportData = [];
|
||||
$reportData[] = ["Date","First Punch-In Time","Last Punch-Out Time","Time in Attendance (Hours)","Time in Time-sheets (Hours)"];
|
||||
$reportData[] = ["Employee:",$employeeObject->first_name." ".$employeeObject->last_name,"","",""];
|
||||
$reportData[] = ["Department:",$company->title,"","",""];
|
||||
$reportData[] = ["Total Days:","","","",""];
|
||||
|
||||
|
||||
//Iterate date range
|
||||
|
||||
$interval = \DateInterval::createFromDateString('1 day');
|
||||
$period = new \DatePeriod(new \DateTime($req['date_start']), $interval, new \DateTime($req['date_end']));
|
||||
$period = new \DatePeriod(new \DateTime($req['date_start']), $interval, (new \DateTime($req['date_end']))->modify('+1 day'));
|
||||
|
||||
$totalHoursOffice = 0;
|
||||
$totalHoursTimeSheets = 0;
|
||||
$totalDaysForThePeriod = 0;
|
||||
|
||||
foreach ($period as $dt) {
|
||||
$dataRow = array();
|
||||
$key = $dt->format("Y-m-d");
|
||||
|
||||
if (!isset($firstTimeInArray[$key])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$totalDaysForThePeriod++;
|
||||
$dataRow[] = $key;
|
||||
|
||||
if (isset($firstTimeInArray[$key])) {
|
||||
@@ -107,8 +135,44 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
||||
$dataRow[] = 0;
|
||||
}
|
||||
|
||||
$totalHoursOffice += $dataRow[3];
|
||||
$totalHoursTimeSheets += $dataRow[4];
|
||||
|
||||
$dataRow[3] = number_format($dataRow[3], 2, '.', '');
|
||||
$dataRow[4] = number_format($dataRow[4], 2, '.', '');
|
||||
|
||||
$reportData[] = $dataRow;
|
||||
}
|
||||
|
||||
$reportData[3][1] = $totalDaysForThePeriod;
|
||||
|
||||
$totalHoursOffice = number_format($totalHoursOffice, 2, '.', '');
|
||||
$totalHoursTimeSheets = number_format($totalHoursTimeSheets, 2, '.', '');
|
||||
|
||||
$reportData[] = ["Total","","",$totalHoursOffice,$totalHoursTimeSheets];
|
||||
|
||||
return $reportData;
|
||||
}
|
||||
|
||||
private function setRequestDatesBasedOnThePeriod($req) {
|
||||
if (empty($req['period'])) {
|
||||
return $req;
|
||||
}
|
||||
|
||||
if ($req['period'] === 'Current Month') {
|
||||
$req['date_start'] = date('Y-m-01', strtotime('now'));
|
||||
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||
} else if ($req['period'] === 'Last Month') {
|
||||
$req['date_start'] = date('Y-m-d', strtotime('first day of last month'));
|
||||
$req['date_end'] = date('Y-m-d', strtotime('last day of last month'));
|
||||
} else if ($req['period'] === 'Last Week') {
|
||||
$req['date_start'] = date("Y-m-d", strtotime("-7 days"));
|
||||
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||
} else if ($req['period'] === 'Last 2 Weeks') {
|
||||
$req['date_start'] = date("Y-m-d", strtotime("-14 days"));
|
||||
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||
}
|
||||
|
||||
return $req;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,11 @@ class StaffDirectory extends Employee
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function isCustomFieldsEnabled()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
public function Insert()
|
||||
{
|
||||
|
||||
@@ -11,10 +11,15 @@ namespace Travel\Common\Model;
|
||||
use Classes\ModuleAccess;
|
||||
use Classes\SettingsManager;
|
||||
use Model\ApproveModel;
|
||||
use Model\CustomFieldTrait;
|
||||
|
||||
class EmployeeTravelRecord extends ApproveModel
|
||||
{
|
||||
use CustomFieldTrait;
|
||||
|
||||
public $table = 'EmployeeTravelRecords';
|
||||
public $objectName = 'Travel Request';
|
||||
protected $allowCustomFields = true;
|
||||
|
||||
public $notificationModuleName = "Travel Management";
|
||||
public $notificationUnitName = "TravelRequest";
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Travel\Common\Model;
|
||||
|
||||
class EmployeeTravelRecordApproval extends EmployeeTravelRecord
|
||||
{
|
||||
protected $allowCustomFields = false;
|
||||
|
||||
// @codingStandardsIgnoreStart
|
||||
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
|
||||
|
||||
Reference in New Issue
Block a user