Release note v16.0

------------------
### Features
 * Advanced Employee Management Module is now included in IceHrm Open Source Edition
 * LDAP Module which was only available in IceHrm Enterprise is now included in open source also
 * Initial implementation of icehrm REST Api for reading employee details
 * Improvements to data filtering
 * Multiple tabs for settings module
 * Overtime reports - now its possible to calculate overtime for employees.compatible with US overtime rules
 * Logout the user if tried accessing an unauthorized module
 * Setting for updating module names

### Fixes
 * Fix issue: classes should be loaded even the module is disabled
 * Deleting the only Admin user is not allowed
 * Fixes for handling non UTF-8
 * Fix for non-mandatory select boxes are shown as mandatory
This commit is contained in:
Thilina Hasantha
2016-04-15 20:24:39 +05:30
parent 301ea64832
commit 31bb455d6f
71 changed files with 7322 additions and 2813 deletions

View File

@@ -23,8 +23,20 @@ Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilin
class EmployeesActionManager extends SubActionManager{
public function get($req){
$profileId = $this->getCurrentProfileId();
$subordinate = new Employee();
$subordinatesCount = $subordinate->Count("supervisor = ? and id = ?",array($profileId, $req->id));
if($this->user->user_level == 'Admin' || $subordinatesCount > 0){
$id = $req->id;
}
$employee = $this->baseService->getElement('Employee',$this->getCurrentProfileId(),$req->map,true);
if(empty($id)){
$id = $profileId;
}
$employee = $this->baseService->getElement('Employee',$id,$req->map,true);
$subordinate = new Employee();
$subordinates = $subordinate->Find("supervisor = ?",array($employee->id));
@@ -53,11 +65,19 @@ class EmployeesActionManager extends SubActionManager{
}
public function deleteProfileImage($req){
if($this->user->user_level == 'Admin' || $this->user->employee == $req->id){
$profileId = $this->getCurrentProfileId();
$subordinate = new Employee();
$subordinatesCount = $subordinate->Count("supervisor = ? and id = ?",array($profileId, $req->id));
if($this->user->user_level == 'Admin' || $this->user->employee == $req->id || $subordinatesCount == 1){
$fs = FileService::getInstance();
$res = $fs->deleteProfileImage($req->id);
return new IceResponse(IceResponse::SUCCESS,$res);
}
return new IceResponse(IceResponse::ERROR,"Not allowed to delete profile image");
}
public function changePassword($req){
@@ -65,8 +85,9 @@ class EmployeesActionManager extends SubActionManager{
if($this->getCurrentProfileId() != $this->user->employee || empty($this->user->employee)){
return new IceResponse(IceResponse::ERROR,"You are not allowed to change passwords of other employees");
}
$user = $this->baseService->getElement('User',$this->user->id);
$user = new User();
$user->Load("id = ?",array($this->user->id));
if(empty($user->id)){
return new IceResponse(IceResponse::ERROR,"Error occured while changing password");
}

View File

@@ -1,59 +1,69 @@
<div class="row-fluid">
<div class="col-xs-12 col-md-3">
<div class="row">
<div class="col-xs-12 col-md-2">
<div class="row-fluid">
<div class="col-xs-12" style="text-align: center;">
<img id="profile_image__id_" src="" class="img-polaroid" style="max-width: 140px;max-height: 140px;">
<img id="profile_image__id_" src="" class="img-polaroid img-thumbnail" style="max-width: 140px;max-height: 140px;">
</div>
</div>
</div>
<div class="col-xs-12 col-md-9">
<div class="col-xs-12 col-md-10">
<div class="row-fluid">
<div class="col-md-12"><h2 id="name"></h2></div>
</div>
<div class="row-fluid">
<div class="col-md-12">
<p>
<i class="fa fa-phone"></i> <span id="mobile_phone"></span>&nbsp;&nbsp;
<i class="fa fa-envelope"></i> <span id="work_email"></span>
</p>
</div>
</div>
<div class="row-fluid">
<div class="col-xs-12" style="font-size:18px;border-bottom: 1px solid #DDD;margin-bottom: 10px;padding-bottom: 10px;">
<span id="name"></span><br/>
<button id="employeeProfileEditInfo" class="btn btn-inverse btn-xs" onclick="modJs.editEmployee();" style="margin-right:10px;">Edit Info</button>
<button id="employeeUploadProfileImage" onclick="showUploadDialog('profile_image__id_','Upload Profile Image','profile_image',_id_,'profile_image__id_','src','url','image');return false;" class="btn btn-xs btn-inverse" type="button" style="margin-right:10px;">Upload Profile Image</button>
<button id="employeeDeleteProfileImage" onclick="modJs.deleteProfileImage(_id_);return false;" class="btn btn-xs btn-inverse" type="button">Delete Profile Image</button>
<button id="employeeUpdatePassword" onclick="modJs.changePassword();return false;" class="btn btn-xs btn-inverse" type="button">Change Password</button>
<button id="employeeProfileEditInfo" class="btn btn-small btn-success" onclick="modJs.editEmployee();" style="margin-right:10px;"><i class="fa fa-edit"></i> Edit Info</button>
<button id="employeeUploadProfileImage" onclick="showUploadDialog('profile_image__id_','Upload Profile Image','profile_image',_id_,'profile_image__id_','src','url','image');return false;" class="btn btn-small btn-primary" type="button" style="margin-right:10px;"><i class="fa fa-upload"></i> Upload Profile Image</button>
<button id="employeeDeleteProfileImage" onclick="modJs.deleteProfileImage(_id_);return false;" class="btn btn-small btn-warning" type="button" style="margin-right:10px;"><i class="fa fa-times"></i> Delete Profile Image</button>
<button id="employeeUpdatePassword" onclick="modJs.changePassword();return false;" class="btn btn-small btn-success" type="button" style="margin-right:10px;"><i class="fa fa-lock"></i> Change Password</button>
</div>
</div>
<div class="row-fluid" style="border-top: 1px;">
<div class="col-xs-6 col-md-4" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;font-size:13px;">Employee Id</label>
<label class="control-label col-xs-12" style="font-size:13px;font-size:13px;">#_label_employee_id_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="employee_id"></label>
</div>
<div class="col-xs-6 col-md-4" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">NIC Number</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_nic_num_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="nic_num"></label>
</div>
<div class="col-xs-6 col-md-4" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">EPF/CPF No</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_ssn_num_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="ssn_num"></label>
</div>
</div>
</div>
</div>
<div class="row-fluid" style="margin-left:10px;">
<div class="col-xs-12">
<hr/>
<span class="label label-inverse" style="font-size:16px;background: #405A6A;">Personal Information</span><br/><br/>
<div class="row" style="margin-left:10px;">
<div class="panel panel-default" style="width:97.5%;">
<div class="panel-heading"><h4>Personal Information</h4></div>
<div class="panel-body">
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Driver's License Number</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_driving_license_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="driving_license"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Other Id</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_other_id_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="other_id"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Birth Day</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_birthday_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="birthday"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Gender</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_gender_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="gender"></label>
</div>
</div>
@@ -61,87 +71,78 @@
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Nationality</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_nationality_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="nationality_Name"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Marital Status</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_marital_status_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="marital_status"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Joined Date</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_joined_date_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="joined_date"></label>
</div>
</div>
</div>
</div>
</div>
<div class="row-fluid" style="margin-left:10px;margin-top:20px;">
<div class="col-xs-12">
<hr/>
<span class="label label-inverse" style="font-size:16px;background: #405A6A;">Contact Information</span><br/><br/>
<div class="row" style="margin-left:10px;margin-top:20px;">
<div class="panel panel-default" style="width:97.5%;">
<div class="panel-heading"><h4>Contact Information</h4></div>
<div class="panel-body">
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Address 1</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_address1_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="address1"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Address 2</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_address2_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="address2"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">City</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_city_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="city"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Country</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_country_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="country_Name"></label>
</div>
</div>
<hr/>
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Postal Code</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_postal_code_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="postal_code"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Home Phone</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_home_phone_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="home_phone"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Mobile Phone</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="mobile_phone"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Work Phone</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_work_phone_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="work_phone"></label>
</div>
</div>
<hr/>
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Work Email</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="work_email"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Private Email</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_private_email_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="private_email"></label>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row-fluid" style="margin-left:10px;margin-top:20px;">
<div class="col-xs-12">
<hr/>
<span class="label label-inverse" style="font-size:16px;background: #405A6A;">Job Details</span><br/><br/>
<div class="row" style="margin-left:10px;margin-top:20px;">
<div class="panel panel-default" style="width:97.5%;">
<div class="panel-heading"><h4>Job Details</h4></div>
<div class="panel-body">
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Job Title</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_job_title_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="job_title_Name"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Employment Status</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_employment_status_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="employment_status_Name"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
@@ -149,17 +150,18 @@
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="supervisor_Name"></label>
</div>
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Subordinates</label>
<label class="control-label col-xs-12" style="font-size:13px;">Direct Reports</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="subordinates"></label>
</div>
</div>
<hr/>
<div class="row-fluid">
<div class="col-xs-6 col-md-3" style="font-size:16px;">
<label class="control-label col-xs-12" style="font-size:13px;">Department</label>
<label class="control-label col-xs-12" style="font-size:13px;">#_label_department_#</label>
<label class="control-label col-xs-12 iceLabel" style="font-size:13px;font-weight: bold;" id="department_Name"></label>
</div>
</div>
</div>
</div>
</div>

View File

@@ -1,17 +1,17 @@
<div class="col-lg-3 col-xs-12">
<!-- small box -->
<div class="small-box bg-aqua">
<div class="small-box bg-red">
<div class="inner">
<h3>My Travel</h3>
<h3>My Profile</h3>
<p>
Management
Edit Details
</p>
</div>
<div class="icon">
<i class="ion ion-plane"></i>
<i class="ion ion-ios7-person"></i>
</div>
<a href="#_moduleLink_#" class="small-box-footer" id="mytravelLink">
Travel Management <i class="fa fa-arrow-circle-right"></i>
<a href="#_moduleLink_#" class="small-box-footer" id="myProfileLink">
Manage Profile <i class="fa fa-arrow-circle-right"></i>
</a>
</div>
</div>

View File

@@ -25,9 +25,32 @@ $moduleName = 'employees';
define('MODULE_PATH',dirname(__FILE__));
include APP_BASE_PATH.'header.php';
include APP_BASE_PATH.'modulejslibs.inc.php';
$fieldNameMap = BaseService::getInstance()->getFieldNameMappings("Employee");
$customFields = BaseService::getInstance()->getCustomFields("Employee");
?>
<script type="text/javascript" src="<?=BASE_URL.'js/raphael-min.js?v='.$jsVersion?>"></script>
<script type="text/javascript" src="<?=BASE_URL.'js/graffle.js?v='.$jsVersion?>"></script>
<script type="text/javascript" src="<?=BASE_URL.'js/d3js/d3.js?v='.$jsVersion?>"></script>
<script type="text/javascript" src="<?=BASE_URL.'js/d3js/d3.layout.js?v='.$jsVersion?>"></script>
<style type="text/css">
.node circle {
cursor: pointer;
fill: #fff;
stroke: steelblue;
stroke-width: 1.5px;
}
.node text {
font-size: 11px;
}
path.link {
fill: none;
stroke: #ccc;
stroke-width: 1.5px;
}
</style>
<div class="span9">
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
@@ -37,20 +60,15 @@ include APP_BASE_PATH.'modulejslibs.inc.php';
<div class="tab-content">
<div class="tab-pane active" id="tabPageEmployee">
<div id="Employee" class="container reviewBlock" data-content="List" style="padding-left:5px;">
<div id="Employee" class="container reviewBlock" data-content="List" style="padding:25px 0px 0px 0px; width:99%;">
</div>
<div id="EmployeeForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
</div>
</div>
<div class="tab-pane" id="tabPageCompanyGraph">
<div id="CompanyGraph" class="reviewBlock" data-content="List" style="padding-left:5px;">
</div>
<div id="CompanyGraphForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
</div>
<div class="tab-pane reviewBlock" id="tabPageCompanyGraph" style="overflow-x: scroll;">
</div>
</div>
@@ -58,6 +76,8 @@ include APP_BASE_PATH.'modulejslibs.inc.php';
<script>
var modJsList = new Array();
modJsList['tabEmployee'] = new EmployeeAdapter('Employee');
modJsList['tabEmployee'].setFieldNameMap(<?=json_encode($fieldNameMap)?>);
modJsList['tabEmployee'].setCustomFields(<?=json_encode($customFields)?>);
modJsList['tabCompanyGraph'] = new CompanyGraphAdapter('CompanyStructure');
var modJs = modJsList['tabEmployee'];

View File

@@ -22,12 +22,57 @@ Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilin
function EmployeeAdapter(endPoint) {
this.initAdapter(endPoint);
this.fieldNameMap = {};
this.hiddenFields = {};
this.tableFields = {};
this.formOnlyFields = {};
this.customFields = [];
}
EmployeeAdapter.inherits(AdapterBase);
this.currentUserId = null;
EmployeeAdapter.method('setFieldNameMap', function(fields) {
var field;
for(var i=0;i<fields.length;i++){
field = fields[i];
this.fieldNameMap[field.name] = field;
if(field.display == "Hidden"){
this.hiddenFields[field.name] = field;
}else{
if(field.display == "Table and Form"){
this.tableFields[field.name] = field;
}else{
this.formOnlyFields[field.name] = field;
}
}
}
});
EmployeeAdapter.method('setCustomFields', function(fields) {
var field, parsed;
for(var i=0;i<fields.length;i++){
field = fields[i];
if(field.display != "Hidden" && field.data != "" && field.data != undefined){
try{
parsed = JSON.parse(field.data);
if(parsed == undefined || parsed == null){
continue;
}else if(parsed.length != 2){
continue;
}else if(parsed[1].type == undefined || parsed[1].type == null){
continue;
}
this.customFields.push(parsed);
}catch(e){
}
}
}
});
EmployeeAdapter.method('getDataMapping', function() {
return [
"id",
@@ -55,7 +100,7 @@ EmployeeAdapter.method('getHeaders', function() {
});
EmployeeAdapter.method('getFormFields', function() {
var fields, newFields = [];
var employee_id, ssn_num, employment_status, job_title, pay_grade, joined_date, department, work_email, country;
if(this.checkPermission("Edit Employee Number") == "Yes"){
@@ -111,8 +156,8 @@ EmployeeAdapter.method('getFormFields', function() {
}else{
country = [ "country", {"label":"Country","type":"placeholder","remote-source":["Country","code","name"]}];
}
return [
fields = [
[ "id", {"label":"ID","type":"hidden","validation":""}],
employee_id,
[ "first_name", {"label":"First Name","type":"text","validation":""}],
@@ -144,6 +189,24 @@ EmployeeAdapter.method('getFormFields', function() {
joined_date,
department
];
for(var i=0;i<this.customFields.length;i++){
fields.push(this.customFields[i]);
}
for(var i=0;i<fields.length;i++){
tempField = fields[i];
if(this.hiddenFields[tempField[0]] == undefined || this.hiddenFields[tempField[0]] == null ){
if(this.fieldNameMap[tempField[0]] != undefined && this.fieldNameMap[tempField[0]] != null){
title = this.fieldNameMap[tempField[0]].textMapped;
tempField[1]['label'] = title;
}
newFields.push(tempField);
}
}
return newFields;
});
EmployeeAdapter.method('getSourceMapping' , function() {
@@ -187,17 +250,28 @@ EmployeeAdapter.method('modEmployeeDeleteProfileImageCallBack', function(data) {
});
EmployeeAdapter.method('modEmployeeGetSuccessCallBack' , function(data) {
var fields = this.getFormFields();
var currentEmpId = data[1];
var userEmpId = data[2];
data = data[0];
var html = this.getCustomTemplate('myDetails.html');
for(var i=0;i<fields.length;i++) {
if(this.fieldNameMap[fields[i][0]] != undefined && this.fieldNameMap[fields[i][0]] != null){
title = this.fieldNameMap[fields[i][0]].textMapped;
html = html.replace("#_label_"+fields[i][0]+"_#",title);
}
}
html = html.replace(/#_.+_#/i,"");
html = html.replace(/_id_/g,data.id);
$("#"+this.getTableName()).html(html);
var fields = this.getFormFields();
for(var i=0;i<fields.length;i++) {
$("#"+this.getTableName()+" #" + fields[i][0]).html(data[fields[i][0]]);
$("#"+this.getTableName()+" #" + fields[i][0]+"_Name").html(data[fields[i][0]+"_Name"]);
}
var subordinates = "";
@@ -217,14 +291,7 @@ EmployeeAdapter.method('modEmployeeGetSuccessCallBack' , function(data) {
}
$("#"+this.getTableName()+" #subordinates").html(subordinates);
$("#"+this.getTableName()+" #nationality_Name").html(data.nationality_Name);
$("#"+this.getTableName()+" #employment_status_Name").html(data.employment_status_Name);
$("#"+this.getTableName()+" #job_title_Name").html(data.job_title_Name);
$("#"+this.getTableName()+" #country_Name").html(data.country_Name);
$("#"+this.getTableName()+" #province_Name").html(data.province_Name);
$("#"+this.getTableName()+" #supervisor_Name").html(data.supervisor_Name);
$("#"+this.getTableName()+" #department_Name").html(data.department_Name);
$("#"+this.getTableName()+" #name").html(data.first_name + " " + data.last_name);
this.currentUserId = data.id;
@@ -318,16 +385,15 @@ EmployeeAdapter.method('changePasswordFailCallBack', function(callBackData,serve
* Company Graph
*/
function CompanyGraphAdapter(endPoint) {
function CompanyStructureAdapter(endPoint) {
this.initAdapter(endPoint);
}
CompanyGraphAdapter.inherits(AdapterBase);
CompanyStructureAdapter.inherits(AdapterBase);
CompanyGraphAdapter.method('getDataMapping', function() {
CompanyStructureAdapter.method('getDataMapping', function() {
return [
"id",
"title",
@@ -338,7 +404,7 @@ CompanyGraphAdapter.method('getDataMapping', function() {
];
});
CompanyGraphAdapter.method('getHeaders', function() {
CompanyStructureAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID","bVisible":false },
{ "sTitle": "Name" },
@@ -349,7 +415,7 @@ CompanyGraphAdapter.method('getHeaders', function() {
];
});
CompanyGraphAdapter.method('getFormFields', function() {
CompanyStructureAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden","validation":""}],
[ "title", {"label":"Name","type":"text","validation":""}],
@@ -361,25 +427,252 @@ CompanyGraphAdapter.method('getFormFields', function() {
];
});
CompanyGraphAdapter.method('createTable', function(elementId) {
var sourceData = this.sourceData;
if(modJs['r'] == undefined || modJs['r'] == null){
modJs['r'] = Raphael("CompanyGraph", 800, 1000);
}else{
return;
}
function CompanyGraphAdapter(endPoint) {
this.initAdapter(endPoint);
this.nodeIdCounter = 0;
}
var r = modJs['r'];
CompanyGraphAdapter.inherits(CompanyStructureAdapter);
for(var i=0; i< sourceData.length; i++){
sourceData[i].parent = sourceData[i]._original[6];
CompanyGraphAdapter.method('convertToTree', function(data) {
var ice = {};
ice['id'] = -1;
ice['title'] = '';
ice['name'] = '';
ice['children'] = [];
var parent = null;
var added = {};
for(var i=0;i<data.length;i++){
data[i].name = data[i].title;
if(data[i].parent != null && data[i].parent != undefined){
parent = this.findParent(data,data[i].parent);
if(parent != null){
if(parent.children == undefined || parent.children == null){
parent.children = [];
}
parent.children.push(data[i]);
}
}
}
var hierarchy = new HierarchyJs();
var nodes = hierarchy.createNodes(sourceData);
hierarchy.createHierarchy(nodes, r);
for(var i=0;i<data.length;i++){
if(data[i].parent == null || data[i].parent == undefined){
ice['children'].push(data[i]);
}
}
return ice;
});
CompanyGraphAdapter.method('findParent', function(data, parent) {
for(var i=0;i<data.length;i++){
if(data[i].title == parent || data[i].title == parent){
return data[i];
}
}
return null;
});
CompanyGraphAdapter.method('createTable', function(elementId) {
$("#tabPageCompanyGraph").html("");
var that = this;
var sourceData = this.sourceData;
//this.fixCyclicParent(sourceData);
var treeData = this.convertToTree(sourceData);
var m = [20, 120, 20, 120],
w = 5000 - m[1] - m[3],
h = 1000 - m[0] - m[2],
root;
var tree = d3.layout.tree()
.size([h, w]);
this.diagonal = d3.svg.diagonal()
.projection(function(d) { return [d.y, d.x]; });
this.vis = d3.select("#tabPageCompanyGraph").append("svg:svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.append("svg:g")
.attr("transform", "translate(" + m[3] + "," + m[0] + ")");
root = treeData;
root.x0 = h / 2;
root.y0 = 0;
function toggleAll(d) {
if (d.children) {
console.log(d.name);
d.children.forEach(toggleAll);
that.toggle(d);
}
}
this.update(root, tree, root);
});
CompanyGraphAdapter.method('update', function(source, tree, root) {
var that = this;
var duration = d3.event && d3.event.altKey ? 5000 : 500;
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse();
// Normalize for fixed-depth.
nodes.forEach(function(d) { d.y = d.depth * 180; });
// Update the nodes<65>
var node = that.vis.selectAll("g.node")
.data(nodes, function(d) { return d.id || (d.id = ++that.nodeIdCounter); });
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; })
.on("click", function(d) { that.toggle(d); that.update(d, tree, root); });
nodeEnter.append("svg:circle")
.attr("r", 1e-6)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeEnter.append("svg:text")
.attr("x", function(d) { return d.children || d._children ? -10 : 10; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; })
.text(function(d) { return d.name; })
.style("fill-opacity", 1e-6);
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; });
nodeUpdate.select("circle")
.attr("r", 4.5)
.style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; });
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; })
.remove();
nodeExit.select("circle")
.attr("r", 1e-6);
nodeExit.select("text")
.style("fill-opacity", 1e-6);
// Update the links<6B>
var link = that.vis.selectAll("path.link")
.data(tree.links(nodes), function(d) { return d.target.id; });
// Enter any new links at the parent's previous position.
link.enter().insert("svg:path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {x: source.x0, y: source.y0};
return that.diagonal({source: o, target: o});
})
.transition()
.duration(duration)
.attr("d", that.diagonal);
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", that.diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {x: source.x, y: source.y};
return that.diagonal({source: o, target: o});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
});
// Toggle children.
CompanyGraphAdapter.method('toggle', function(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else {
d.children = d._children;
d._children = null;
}
});
CompanyGraphAdapter.method('getSourceDataById', function(id) {
for(var i=0; i< this.sourceData.length; i++){
if(this.sourceData[i].id == id){
return this.sourceData[i];
}
}
return null;
});
CompanyGraphAdapter.method('fixCyclicParent', function(sourceData) {
var errorMsg = "";
for(var i=0; i< sourceData.length; i++){
var obj = sourceData[i];
var curObj = obj;
var parentIdArr = {};
parentIdArr[curObj.id] = 1;
while(curObj.parent != null && curObj.parent != undefined){
var parent = this.getSourceDataById(curObj.parent);
if(parent == null){
break;
}else if(parentIdArr[parent.id] == 1){
errorMsg = obj.title +"'s parent structure set to "+parent.title+"<br/>";
obj.parent = null;
break;
}
parentIdArr[parent.id] = 1;
curObj = parent;
}
}
if(errorMsg != ""){
this.showMessage("Company Structure is having a cyclic dependency","We found a cyclic dependency due to following reasons:<br/>"+errorMsg);
return false;
}
return true;
});

View File

@@ -4,6 +4,7 @@
"order":"2",
"icon":"fa-user",
"user_levels":["Admin","Manager","Employee"],
"dashboardPosition":101,
"permissions":
{

View File

@@ -1,7 +1,10 @@
{
"Personal Information":"fa-male",
"Subordinates":"fa-user",
"Leave":"fa-calendar-o",
"Time Management":"fa-clock-o",
"Documents":"fa-files-o",
"Company":"fa-building",
"Training":"fa-briefcase",
"Travel Management":"fa-plane",
"Finance":"fa-money"
}
"Finance":"fa-money"
}

View File

@@ -32,8 +32,6 @@ EmployeeSalaryAdapter.method('getDataMapping', function() {
return [
"id",
"component",
"pay_frequency",
"currency",
"amount",
"details"
];
@@ -43,8 +41,6 @@ EmployeeSalaryAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Salary Component" },
{ "sTitle": "Pay Frequency"},
{ "sTitle": "Currency"},
{ "sTitle": "Amount"},
{ "sTitle": "Details"}
];
@@ -54,8 +50,6 @@ EmployeeSalaryAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden"}],
[ "component", {"label":"Salary Component","type":"select2","remote-source":["SalaryComponent","id","name"]}],
[ "pay_frequency", {"label":"Pay Frequency","type":"select","source":[["Hourly","Hourly"],["Daily","Daily"],["Bi Weekly","Bi Weekly"],["Weekly","Weekly"],["Semi Monthly","Semi Monthly"],["Monthly","Monthly"]]}],
[ "currency", {"label":"Currency","type":"select","remote-source":["CurrencyType","id","name"]}],
[ "amount", {"label":"Amount","type":"text","validation":"float"}],
[ "details", {"label":"Details","type":"textarea","validation":"none"}]
];

View File

@@ -1,59 +0,0 @@
<?php
class TravelActionManager extends ApproveModuleActionManager{
public function getModelClass(){
return "EmployeeTravelRecord";
}
public function getItemName(){
return "TravelRequest";
}
public function getModuleName(){
return "Travel Management";
}
public function getModuleTabUrl(){
return "g=admin&n=travel&m=admin_Employees#tabEmployeeTravelRecord";
}
}
/*
class TravelActionManager extends SubActionManager{
public function cancelTravel($req){
$employee = $this->baseService->getElement('Employee',$this->getCurrentProfileId(),null,true);
$employeeTravel = new EmployeeTravelRecord();
$employeeTravel->Load("id = ?",array($req->id));
if($employeeTravel->id != $req->id){
return new IceResponse(IceResponse::ERROR,"Travel record not found");
}
if($this->user->user_level != 'Admin' && $this->getCurrentProfileId() != $employeeTravel->employee){
return new IceResponse(IceResponse::ERROR,"Only an admin or owner of the travel request can do this");
}
if($employeeTravel->status != 'Approved'){
return new IceResponse(IceResponse::ERROR,"Only an approved travel request can be cancelled");
}
$employeeTravel->status = 'Cancellation Requested';
$ok = $employeeTravel->Save();
if(!$ok){
LogManager::getInstance()->error("Error occured while cancelling the travel:".$employeeTravel->ErrorMsg());
return new IceResponse(IceResponse::ERROR,"Error occurred while cancelling the travel request. Please contact admin.");
}
$this->baseService->audit(IceConstants::AUDIT_ACTION, "Travel cancellation \ start:".$employeeTravel->date_start."\ end:".$employeeTravel->date_end);
$notificationMsg = $employee->first_name." ".$employee->last_name." cancelled a travel. Visit travel management module to approve";
$this->baseService->notificationManager->addNotification($employee->supervisor,$notificationMsg,'{"type":"url","url":"g=admin&n=travel&m=admin_Employees#tabEmployeeTravelRecord"}',
"Travel Module", null, false, true);
return new IceResponse(IceResponse::SUCCESS,$employeeTravel);
}
}
*/

View File

@@ -1,24 +0,0 @@
<?php
if (!class_exists('TravelModulesManager')) {
class TravelModulesManager extends AbstractModuleManager{
public function initializeUserClasses(){
}
public function initializeFieldMappings(){
}
public function initializeDatabaseErrorMappings(){
}
public function setupModuleClassDefinitions(){
}
}
}

View File

@@ -1,66 +0,0 @@
<?php
/*
This file is part of iCE Hrm.
iCE Hrm is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
iCE Hrm is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with iCE Hrm. If not, see <http://www.gnu.org/licenses/>.
------------------------------------------------------------------
Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd]
Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah)
*/
$moduleName = 'travel';
$moduleMainName = "EmployeeTravelRecord";
$moduleItemName = "Travel Request";
define('MODULE_PATH',dirname(__FILE__));
include APP_BASE_PATH.'header.php';
include APP_BASE_PATH.'modulejslibs.inc.php';
?><div class="span9">
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
<li class="active"><a id="tab<?=$moduleMainName?>" href="#tabPage<?=$moduleMainName?>">Travel Requests</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tabPage<?=$moduleMainName?>">
<div id="<?=$moduleMainName?>" class="reviewBlock" data-content="List" style="padding-left:5px;">
</div>
<div id="<?=$moduleMainName?>Form" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
</div>
</div>
</div>
</div>
<script>
var modJsList = new Array();
modJsList['tab<?=$moduleMainName?>'] = new <?=$moduleMainName?>Adapter('<?=$moduleMainName?>','<?=$moduleMainName?>');
<?php if(isset($modulePermissions['perm']['Add '.$moduleItemName]) && $modulePermissions['perm']['Add '.$moduleItemName] == "No"){?>
modJsList['tab<?=$moduleMainName?>'].setShowAddNew(false);
<?php }?>
<?php if(isset($modulePermissions['perm']['Delete '.$moduleItemName]) && $modulePermissions['perm']['Delete '.$moduleItemName] == "No"){?>
modJsList['tab<?=$moduleMainName?>'].setShowDelete(false);
<?php }?>
<?php if(isset($modulePermissions['perm']['Edit '.$moduleItemName]) && $modulePermissions['perm']['Edit '.$moduleItemName] == "No"){?>
modJsList['tab<?=$moduleMainName?>'].setShowEdit(false);
<?php }?>
var modJs = modJsList['tab<?=$moduleMainName?>'];
</script>
<?php include APP_BASE_PATH.'footer.php';?>

View File

@@ -1,158 +0,0 @@
/*
This file is part of iCE Hrm.
Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd]
Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah)
*/
function EmployeeImmigrationAdapter(endPoint) {
this.initAdapter(endPoint);
}
EmployeeImmigrationAdapter.inherits(AdapterBase);
EmployeeImmigrationAdapter.method('getDataMapping', function() {
return [
"id",
"document",
"documentname",
"valid_until",
"status"
];
});
EmployeeImmigrationAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Document" },
{ "sTitle": "Document Id" },
{ "sTitle": "Valid Until"},
{ "sTitle": "Status"}
];
});
EmployeeImmigrationAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden"}],
[ "document", {"label":"Document","type":"select2","remote-source":["ImmigrationDocument","id","name"]}],
[ "documentname", {"label":"Document Id","type":"text","validation":""}],
[ "valid_until", {"label":"Valid Until","type":"date","validation":"none"}],
[ "status", {"label":"Status","type":"select","source":[["Active","Active"],["Inactive","Inactive"],["Draft","Draft"]]}],
[ "details", {"label":"Details","type":"textarea","validation":"none"}],
[ "attachment1", {"label":"Attachment 1","type":"fileupload","validation":"none"}],
[ "attachment2", {"label":"Attachment 2","type":"fileupload","validation":"none"}],
[ "attachment3", {"label":"Attachment 3","type":"fileupload","validation":"none"}]
];
});
function EmployeeTravelRecordAdapter(endPoint) {
this.initAdapter(endPoint);
}
EmployeeTravelRecordAdapter.inherits(AdapterBase);
EmployeeTravelRecordAdapter.method('getDataMapping', function() {
return [
"id",
"type",
"purpose",
"travel_from",
"travel_to",
"travel_date",
"return_date",
"status"
];
});
EmployeeTravelRecordAdapter.method('getHeaders', function() {
return [
{ "sTitle": "ID" ,"bVisible":false},
{ "sTitle": "Travel Type" },
{ "sTitle": "Purpose" },
{ "sTitle": "From"},
{ "sTitle": "To"},
{ "sTitle": "Travel Date"},
{ "sTitle": "Return Date"},
{ "sTitle": "Status"}
];
});
EmployeeTravelRecordAdapter.method('getFormFields', function() {
return [
[ "id", {"label":"ID","type":"hidden"}],
[ "type", {"label":"Travel Type","type":"select","source":[["Local","Local"],["International","International"]]}],
[ "purpose", {"label":"Purpose of Travel","type":"textarea","validation":""}],
[ "travel_from", {"label":"Travel From","type":"text","validation":""}],
[ "travel_to", {"label":"Travel To","type":"text","validation":""}],
[ "travel_date", {"label":"Travel Date","type":"datetime","validation":""}],
[ "return_date", {"label":"Return Date","type":"datetime","validation":""}],
[ "details", {"label":"Notes","type":"textarea","validation":"none"}],
[ "currency", {"label":"Currency","type":"select2","allow-null":false,"remote-source":["CurrencyType","id","code"]}],
[ "funding", {"label":"Total Funding Proposed","type":"text","validation":"float"}],
[ "attachment1", {"label":"Itinerary / Cab Receipt","type":"fileupload","validation":"none"}],
[ "attachment2", {"label":"Other Attachment 1","type":"fileupload","validation":"none"}],
[ "attachment3", {"label":"Other Attachment 2","type":"fileupload","validation":"none"}]
];
});
EmployeeTravelRecordAdapter.method('getActionButtonsHtml', function(id,data) {
var editButton = '<img class="tableActionButton" src="_BASE_images/edit.png" style="cursor:pointer;" rel="tooltip" title="Edit" onclick="modJs.edit(_id_);return false;"></img>';
var deleteButton = '<img class="tableActionButton" src="_BASE_images/delete.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Delete" onclick="modJs.deleteRow(_id_);return false;"></img>';
var requestCancellationButton = '<img class="tableActionButton" src="_BASE_images/delete.png" style="margin-left:15px;cursor:pointer;" rel="tooltip" title="Cancel Travel Request" onclick="modJs.cancelTravel(_id_);return false;"></img>';
var html = '<div style="width:80px;">_edit__delete_</div>';
if(this.showDelete){
if(data[7] == "Approved"){
html = html.replace('_delete_',requestCancellationButton);
}else{
html = html.replace('_delete_',deleteButton);
}
}else{
html = html.replace('_delete_','');
}
if(this.showEdit){
html = html.replace('_edit_',editButton);
}else{
html = html.replace('_edit_','');
}
html = html.replace(/_id_/g,id);
html = html.replace(/_BASE_/g,this.baseUrl);
return html;
});
EmployeeTravelRecordAdapter.method('cancelTravel', function(id) {
var that = this;
var object = {};
object['id'] = id;
var reqJson = JSON.stringify(object);
var callBackData = [];
callBackData['callBackData'] = [];
callBackData['callBackSuccess'] = 'cancelSuccessCallBack';
callBackData['callBackFail'] = 'cancelFailCallBack';
this.customAction('cancelTravel','modules=travel',reqJson,callBackData);
});
EmployeeTravelRecordAdapter.method('cancelSuccessCallBack', function(callBackData) {
this.showMessage("Successful", "Travel request cancellation request sent");
this.get([]);
});
EmployeeTravelRecordAdapter.method('cancelFailCallBack', function(callBackData) {
this.showMessage("Error Occurred while cancelling Travel request", callBackData);
});

View File

@@ -1,23 +0,0 @@
{
"label":"Travel",
"menu":"Travel Management",
"order":"1",
"icon":"fa-plane",
"user_levels":["Admin","Manager","Employee"],
"dashboardPosition":107,
"permissions":
{
"Manager":{
"Add Travel Request":"Yes",
"Edit Travel Request":"Yes",
"Delete Travel Request":"Yes"
},
"Employee":{
"Add Travel Request":"Yes",
"Edit Travel Request":"Yes",
"Delete Travel Request":"Yes"
}
}
}