diff --git a/core-ext/scripts/icehrm_master_data.sql b/core-ext/scripts/icehrm_master_data.sql
index 949f4478..2d6e7041 100644
--- a/core-ext/scripts/icehrm_master_data.sql
+++ b/core-ext/scripts/icehrm_master_data.sql
@@ -816,6 +816,10 @@ INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `
'["department","date_start","date_end"]', 'Class','Employee Information');
+INSERT INTO `Settings` (`name`, `value`, `description`, `meta`) VALUES
+ ('Travel: Pre-Approve Travel Request', '0', '','["value", {"label":"Value","type":"select","source":[["1","Yes"],["0","No"]]}]');
+
+
INSERT INTO `Reports` (`name`, `details`, `parameters`, `query`, `paramOrder`, `type`,`report_group`) VALUES
('Employee Time Sheet Report', 'This report list all employee time sheets by employee and date range', '[\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[ "status", {"label":"Status","allow-null":true,"null-label":"All Status","type":"select","source":[["Approved","Approved"],["Pending","Pending"],["Rejected","Rejected"]]}]\r\n]', 'EmployeeTimeSheetData', '["employee","date_start","date_end","status"]', 'Class','Time Management');
diff --git a/ext/admin/travel/api/TravelActionManager.php b/ext/admin/travel/api/TravelActionManager.php
new file mode 100644
index 00000000..40d3a10e
--- /dev/null
+++ b/ext/admin/travel/api/TravelActionManager.php
@@ -0,0 +1,19 @@
+addUserClass("EmployeeImmigration");
+ $this->addUserClass("EmployeeTravelRecord");
+ }
+ }
+
+ public function initializeFieldMappings(){
+ $this->addFileFieldMapping('EmployeeImmigration', 'attachment1', 'name');
+ $this->addFileFieldMapping('EmployeeImmigration', 'attachment2', 'name');
+ $this->addFileFieldMapping('EmployeeImmigration', 'attachment3', 'name');
+
+ $this->addFileFieldMapping('EmployeeTravelRecord', 'attachment1', 'name');
+ $this->addFileFieldMapping('EmployeeTravelRecord', 'attachment2', 'name');
+ $this->addFileFieldMapping('EmployeeTravelRecord', 'attachment3', 'name');
+ }
+
+ public function initializeDatabaseErrorMappings(){
+
+ }
+
+ public function setupModuleClassDefinitions(){
+
+ $this->addModelClass('ImmigrationDocument');
+ $this->addModelClass('EmployeeImmigration');
+ $this->addModelClass('EmployeeTravelRecord');
+
+ }
+
+ }
+}
+
+
+if (!class_exists('ImmigrationDocument')) {
+ class ImmigrationDocument extends ICEHRM_Record {
+ var $_table = 'ImmigrationDocuments';
+
+ public function getAdminAccess(){
+ return array("get","element","save","delete");
+ }
+
+ public function getManagerAccess(){
+ return array("get","element","save","delete");
+ }
+
+ public function getUserAccess(){
+ return array("get");
+ }
+
+ public function getUserOnlyMeAccess(){
+ return array("get","element");
+ }
+ }
+}
+
+if (!class_exists('EmployeeImmigration')) {
+ class EmployeeImmigration extends ICEHRM_Record {
+ var $_table = 'EmployeeImmigrations';
+
+ public function getAdminAccess(){
+ return array("get","element","save","delete");
+ }
+
+ public function getManagerAccess(){
+ return array("get","element","save","delete");
+ }
+
+ public function getUserAccess(){
+ return array("get");
+ }
+
+ public function getUserOnlyMeAccess(){
+ return array("element","save","delete");
+ }
+ }
+}
+
+
+if (!class_exists('EmployeeTravelRecord')) {
+ class EmployeeTravelRecord extends ApproveModel
+ {
+ var $_table = 'EmployeeTravelRecords';
+
+ var $notificationModuleName = "Travel Management";
+ var $notificationUnitName = "TravelRequest";
+ var $notificationUnitPrefix = "A";
+ var $notificationUnitAdminUrl = "g=admin&n=travel&m=admin_Employees";
+ var $preApproveSettingName = "Travel: Pre-Approve Travel Request";
+
+ public function getAdminAccess()
+ {
+ return array("get", "element", "save", "delete");
+ }
+
+ public function getManagerAccess()
+ {
+ return array("get", "element", "save", "delete");
+ }
+
+ public function getUserAccess()
+ {
+ return array("get");
+ }
+
+ public function getUserOnlyMeAccess()
+ {
+ return array("element", "save", "delete");
+ }
+
+ public function fieldsNeedToBeApproved()
+ {
+ return array(
+ "travel_from",
+ "travel_to",
+ "travel_date",
+ "return_date",
+ "funding",
+ "currency"
+ );
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ext/admin/travel/dashboard.html b/ext/admin/travel/dashboard.html
new file mode 100644
index 00000000..1c14dc56
--- /dev/null
+++ b/ext/admin/travel/dashboard.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+ Travel
+
+
+ Requests
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ext/admin/travel/index.php b/ext/admin/travel/index.php
new file mode 100644
index 00000000..62a033a8
--- /dev/null
+++ b/ext/admin/travel/index.php
@@ -0,0 +1,78 @@
+.
+
+------------------------------------------------------------------
+
+Original work Copyright (c) 2012 [Gamonoid Media Pvt. Ltd]
+Developer: Thilina Hasantha (thilina.hasantha[at]gmail.com / facebook.com/thilinah)
+ */
+
+$moduleName = 'travel';
+define('MODULE_PATH',dirname(__FILE__));
+include APP_BASE_PATH.'header.php';
+include APP_BASE_PATH.'modulejslibs.inc.php';
+
+$options = array();
+$options['setRemoteTable'] = 'true';
+
+$moduleBuilder = new ModuleBuilder();
+$moduleBuilder->addModuleOrGroup(new ModuleTab('EmployeeTravelRecord','EmployeeTravelRecord','Travel Requests','EmployeeTravelRecordAdapter','','',true,$options));
+echo UIManager::getInstance()->renderModule($moduleBuilder);
+
+
+$itemName = 'TravelRequest';
+$moduleName = 'Travel Management';
+$itemNameLower = strtolower($itemName);
+
+$statuses = array("Approved","Pending","Rejected","Cancelled");
+
+?>
+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);
+ }
+}
+*/
\ No newline at end of file
diff --git a/ext/modules/travel/api/TravelModulesManager.php b/ext/modules/travel/api/TravelModulesManager.php
new file mode 100644
index 00000000..a7729196
--- /dev/null
+++ b/ext/modules/travel/api/TravelModulesManager.php
@@ -0,0 +1,24 @@
+
+
+
+
+
My Travel
+
+ Management
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ext/modules/travel/index.php b/ext/modules/travel/index.php
new file mode 100644
index 00000000..b348bc1e
--- /dev/null
+++ b/ext/modules/travel/index.php
@@ -0,0 +1,66 @@
+.
+
+------------------------------------------------------------------
+
+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';
+?>
+
+
\ No newline at end of file
diff --git a/ext/modules/travel/lib.js b/ext/modules/travel/lib.js
new file mode 100644
index 00000000..ce47b55a
--- /dev/null
+++ b/ext/modules/travel/lib.js
@@ -0,0 +1,158 @@
+/*
+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 = '
';
+ var deleteButton = '
';
+ var requestCancellationButton = '
';
+
+ var html = '_edit__delete_
';
+
+ 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);
+});
+
diff --git a/ext/modules/travel/meta.json b/ext/modules/travel/meta.json
new file mode 100644
index 00000000..37069e21
--- /dev/null
+++ b/ext/modules/travel/meta.json
@@ -0,0 +1,23 @@
+{
+"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"
+ }
+ }
+
+}
\ No newline at end of file