diff --git a/TimeSheet.php b/TimeSheet.php new file mode 100644 index 0000000..df5d37f --- /dev/null +++ b/TimeSheet.php @@ -0,0 +1,214 @@ +xero = $xero; + $this->end_date = $end_date; + $this->cal_start(); //set start_date; + $this->get_remote_timesheets(); + } + + private function cal_start(){ + $d = new \DateTime($this->end_date); + $d->modify("-13 days"); + $this->start_date = $d->format("Y-m-d"); +// wp_send_json(array( +// 'start'=> $this->start_date, +// 'finish'=> $this->end_date, +// )); + } + + private function get_remote_timesheets() + { + $this->remote_timesheets = $this->xero->load('PayrollAU\\Timesheet') + ->where('EndDate==DateTime.Parse("'. $this->end_date .'")') + ->execute(); + } + + public function get_xero_timesheet() + { + return $this->remote_timesheets; + } + + public function get_local_timesheet() + { + return $this->local_timesheets; + } + + public function set_local_timesheet($lines) + { + $this->local_timesheets = []; + //convert $val to Timesheet format; + foreach ($lines as $staff_login => $rateshours){ + $ts = ""; + if (array_key_exists($staff_login, $this->local_timesheets)){ + $ts = $this->local_timesheets[$staff_login]; + }else{ + $ts = new \XeroPHP\Models\PayrollAU\Timesheet($this->xero); + $ts->setEmployeeID($staff_login) + ->setTimeSheetID($this->get_timesheet_id_by_employee_id($staff_login)) + ->setStartDate(new \DateTime($this->start_date)) + ->setEndDate(new \DateTime($this->end_date)) + ->setStatus("DRAFT"); + } + //adding lines + foreach ($rateshours as $rateid => $hours) + { + $ts_line = new \XeroPHP\Models\PayrollAU\Timesheet\TimesheetLine($this->xero); + $ts_line->setEarningsRateID($rateid); + for ($i=0; $i<14; $i++){ + $ts_line->addNumberOfUnit($hours[$i]); + } + $ts->addTimesheetLine($ts_line); + } + //update this timesheet; + $this->local_timesheets[$staff_login] = $ts; + } + } + + public function save_to_xero() + { + $to_save=[]; + foreach ( $this->local_timesheets as $t){ + $t->setDirty('EmployeeID'); + $t->setDirty('StartDate'); + $t->setDirty('EndDate'); + $t->setDirty('TimesheetLines'); + $t->setDirty('Status'); + $t->setDirty('Hours'); + $t->setDirty('TimesheetID'); + $t->setStatus('DRAFT'); + $to_save[]=$t; + } + //empty remote timesheet which are not available in local + // + //some of buddy timesheets might be removed from local already + //we cannot delete it but we can set it to 0 hours + // + foreach ($this->remote_timesheets as $ts) + { + $staff_login = $ts->getEmployeeID(); + if (!array_key_exists($staff_login, $this->local_timesheets)){//not found + //we create empty timesheets for him/her + $empty = new \XeroPHP\Models\PayrollAU\Timesheet($this->xero); + $empty->setEmployeeID($staff_login) + ->setTimeSheetID($ts->getTimesheetID()) + ->setStartDate(new \DateTime($this->start_date)) + ->setEndDate(new \DateTime($this->end_date)) + ->setStatus("DRAFT"); + + if ( $ts->getStatus() == "DRAFT" ){//good, we can save it; + $to_save[] = $empty;//add it to save + }else{ + $staff_name = \Biukop\AcareOffice::get_user_name_by_login($staff_login); + $msg = sprintf("%s : %s is APPROVED, but needs to be empty it", + $staff_name, + $ts->getTimeSheetID()); + \Biukop\AcareOffice::log($msg); + } + } + } + $this->xero->saveAll($to_save, false); + } + + private function get_timesheet_id_by_employee_id($id) + { + foreach ($this->remote_timesheets as $ts) + { + $staff_login = $ts->getEmployeeID(); + if($staff_login == $id){ + return $ts->getTimesheetID(); + } + } + return NULL; + } + + public function warning_timesheet() + { + return $this->warning_timesheets; + } + + private function approve_all(){ + $to_save=[]; + foreach ( $this->local_timesheets as $t){ + $t->setDirty('EmployeeID'); + $t->setDirty('StartDate'); + $t->setDirty('EndDate'); + $t->setDirty('TimesheetLines'); + $t->setDirty('Status'); + $t->setDirty('Hours'); + $t->setDirty('TimesheetID'); + $t->setStatus('APPROVED'); + $to_save[]=$t; + } + $this->xero->saveAll($to_save, false); + } + + public function get_buddy_timesheets($employee_id, $start, $end) + { + foreach ($this->remote_timesheets as $t){ + if ( $t->getEmployeeID() == $employee_id && + $t->getStartDate()->format('Y-m-d') == $start->format('Y-m-d') && + $t->getEndDate()->format('Y-m-d') == $end->format('Y-m-d') ) + { + return $t; + } + } + return NULL; //not found; + } + + private function get_buddy_timesheet_by_ts($t) + { + $employee_id = $t->getEmployeeID(); + $start = $t->getStartDate(); + $end = $t->getEndDate(); + return $this->get_buddy_timesheets($employee_id, $start, $end); + } + + public function main(){ + $this->warning_timesheets = []; + $this->buddy_timesheets = []; + $this->local_timesheets = $this->create_timesheet_from_db( + new DateTime("2019-07-01"), + new DateTime("2019-07-14") + ); + $length = count($this->local_timesheets); + $to_save =[]; + for ($i =0; $i < $length; $i++) + { + $me = $this->local_timesheets[$i]; + $buddy = $this->get_buddy_timesheet_by_ts($me); + + $this->buddy_timesheets[$i] = $buddy; + + if ( $buddy != NULL ) { + $timesheet_id = $buddy->getTimeSheetID(); + $me->setTimeSheetID($timesheet_id); + if ( $buddy->getStatus() != 'DRAFT'){ + $this->warning_timesheets[]=$me; + continue; + }else{ + $to_save[]=$me; + } + }else{ + $to_save[]=$me; + } + + } + $this->xero->saveAlL($to_save, false); //false do not check GUID, always use POST; not PUT + //$this->approve_all(); + } + + + +} diff --git a/Xero.php b/Xero.php index 7e09f84..5af19d7 100644 --- a/Xero.php +++ b/Xero.php @@ -43,6 +43,11 @@ class Xero { $this->xero = new PrivateApplication($this->office_config()); } + public function get_xero_handle() + { + return $this->xero; + } + public function getClients($contact_group_id){ $xero = $this->xero; $cg = $xero->loadByGUID("Accounting\\ContactGroup", $contact_group_id); @@ -68,7 +73,7 @@ class Xero { } - + // //sync users to wordpress system //does not work for too many users or employees @@ -302,7 +307,11 @@ class Xero { /* sync payitems to wp options */ public function init_wp(){ - $this->sync_payitem(); + try{ + $this->sync_payitem(); + }catch(\XeroPHP\Remote\Exception $e){ + + } } private function sync_payitem(){ @@ -350,4 +359,12 @@ class Xero { return $diff < $this->minimum_sync_interval_in_seconds; //default 10 minutes } + + public function get_payroll_calendar() + { + $id = "33dc7df5-3060-4d76-b4da-57c20685d77d"; //fortnightly + $pc = $this->xero->loadByGUID('PayrollAU\\PayrollCalendar', $id); + return $pc; + } + } \ No newline at end of file diff --git a/css/bts_timesheet.css b/css/bts_timesheet.css index a7588f9..b7fd08b 100644 --- a/css/bts_timesheet.css +++ b/css/bts_timesheet.css @@ -240,7 +240,7 @@ div.peopleitem label:hover :checked + .card { background-color: white; box-shadow: inset 0px 0px 2px dotted white; border-radius: 100px; - background-image: url(http://acaresydney.com.au/wp-content/uploads/2019/06/xero.png); + background-image: url(../img/xero.png); background-size: 40px; box-shadow: 0px 0px 10px white; } @@ -264,7 +264,7 @@ div.peopleitem label:hover :checked + .card { background-color: white; box-shadow: inset 0px 0px 2px black; border-radius: 100px; - background-image: url(http://acaresydney.com.au/wp-content/uploads/2019/06/wnet.png); + background-image: url(../img/wnet.png); background-size: 40px; box-shadow: 0px 0px 10px white; } @@ -278,7 +278,7 @@ div.peopleitem label:hover :checked + .card { background-color: white; box-shadow: inset 0px 0px 2px black; border-radius: 100px; - background-image: url(http://acaresydney.com.au/wp-content/uploads/2019/08/csv.png); + background-image: url(../img/csv.png); background-size: 40px; box-shadow: 0px 0px 10px white; } diff --git a/css/xeroc.css b/css/xeroc.css new file mode 100644 index 0000000..fc1b851 --- /dev/null +++ b/css/xeroc.css @@ -0,0 +1,107 @@ +@CHARSET "UTF-8"; + +.container{ + width:100%; +} + +#cstart, #cfinish, #paydate{ + color: black; + font-weight:900; + width:100%; + background-color: #EDEDED; + border:none; +} + +.hidden{ + display:none; +} + +td.sync_detail{ + padding:0px; +} + +table.hours{ + margin-bottom:0px; +} + +table.blueTable { + border: 1px solid #1C6EA4; + background-color: #EEEEEE; + width: 100%; + text-align: left; + border-collapse: collapse; +} +table.blueTable td, table.blueTable th { + border: 1px solid #AAAAAA; + padding: 3px 2px; +} +table.blueTable tbody td { + font-size: 13px; +} +table.blueTable tr:nth-child(even) { + background: #D0E4F5; +} +table.blueTable thead { + background: #1C6EA4; + background: -moz-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%); + background: -webkit-linear-gradient(top, #5592bb 0%, #327cad 66%, #1C6EA4 100%); + background: linear-gradient(to bottom, #5592bb 0%, #327cad 66%, #1C6EA4 100%); + border-bottom: 2px solid #444444; +} +table.blueTable thead th { + font-size: 15px; + font-weight: bold; + color: #FFFFFF; + border-left: 2px solid #D0E4F5; +} +table.blueTable thead th:first-child { + border-left: none; +} + +table.blueTable tfoot { + font-size: 14px; + font-weight: bold; + color: #FFFFFF; + background: #D0E4F5; + background: -moz-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + background: -webkit-linear-gradient(top, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + background: linear-gradient(to bottom, #dcebf7 0%, #d4e6f6 66%, #D0E4F5 100%); + border-top: 2px solid #444444; +} +table.blueTable tfoot td { + font-size: 14px; +} +table.blueTable tfoot .links { + text-align: right; +} +table.blueTable tfoot .links a{ + display: inline-block; + background: #1C6EA4; + color: #FFFFFF; + padding: 2px 8px; + border-radius: 5px; +} + + +.week1color { + color: black; + + /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#ebe9f9+0,d8d0ef+50,cec7ec+51,c1bfea+100;Purple+3D+%231 */ + background: #ebe9f9; /* Old browsers */ + background: -moz-linear-gradient(top, #ebe9f9 0%, #d8d0ef 50%, #cec7ec 51%, #c1bfea 100%); /* FF3.6-15 */ + background: -webkit-linear-gradient(top, #ebe9f9 0%,#d8d0ef 50%,#cec7ec 51%,#c1bfea 100%); /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(to bottom, #ebe9f9 0%,#d8d0ef 50%,#cec7ec 51%,#c1bfea 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebe9f9', endColorstr='#c1bfea',GradientType=0 ); /* IE6-9 */ +} + + +.week2color { + color: white; + + /* Permalink - use to edit and share this gradient: https://colorzilla.com/gradient-editor/#627d4d+0,1f3b08+100;Olive+3D */ + background: #627d4d; /* Old browsers */ + background: -moz-linear-gradient(top, #627d4d 0%, #1f3b08 100%); /* FF3.6-15 */ + background: -webkit-linear-gradient(top, #627d4d 0%,#1f3b08 100%); /* Chrome10-25,Safari5.1-6 */ + background: linear-gradient(to bottom, #627d4d 0%,#1f3b08 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#627d4d', endColorstr='#1f3b08',GradientType=0 ); /* IE6-9 */ +} \ No newline at end of file diff --git a/html/bts_staff_hours_template.html b/html/bts_staff_hours_template.html new file mode 100644 index 0000000..46a8f67 --- /dev/null +++ b/html/bts_staff_hours_template.html @@ -0,0 +1,68 @@ +{{#lines}} +
| {{days_1}} | +{{days_2}} | +{{days_3}} | +{{days_4}} | +{{days_5}} | +{{days_6}} | +{{days_7}} | +{{days_8}} | +{{days_9}} | +{{days_10}} | +{{days_11}} | +{{days_12}} | +{{days_13}} | +{{days_14}} | + + +
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{local_1}} | +{{local_2}} | +{{local_3}} | +{{local_4}} | +{{local_5}} | +{{local_6}} | +{{local_7}} | +{{local_8}} | +{{local_9}} | +{{local_10}} | +{{local_11}} | +{{local_12}} | +{{local_13}} | +{{local_14}} | +
|
+ To Xero
+
+
+ |
+ |||||||||||||
| {{xero_1}} | +{{xero_2}} | +{{xero_3}} | +{{xero_4}} | +{{xero_5}} | +{{xero_6}} | +{{xero_7}} | +{{xero_8}} | +{{xero_9}} | +{{xero_10}} | +{{xero_11}} | +{{xero_12}} | +{{xero_13}} | +{{xero_14}} | +