Browse Source

xero sync

master
patrick 6 years ago
parent
commit
3174c9be4e
10 changed files with 703 additions and 10 deletions
  1. +214
    -0
      TimeSheet.php
  2. +19
    -2
      Xero.php
  3. +3
    -3
      css/bts_timesheet.css
  4. +107
    -0
      css/xeroc.css
  5. +68
    -0
      html/bts_staff_hours_template.html
  6. BIN
      img/csv.png
  7. BIN
      img/wnet.png
  8. BIN
      img/xero.png
  9. +79
    -0
      js/xeroc.js
  10. +213
    -5
      ts.php

+ 214
- 0
TimeSheet.php View File

@@ -0,0 +1,214 @@
<?php

namespace Biukop;

class TimeSheet{
private $xero ;
private $start_date;
private $end_date;
private $remote_timesheets;
private $local_timesheets =[];
private $buddy_timesheets =[];
private $warning_timesheets =[];
public function __construct($xero, $end_date){
$this->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();
}

}

+ 19
- 2
Xero.php View File

@@ -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;
}
}

+ 3
- 3
css/bts_timesheet.css View File

@@ -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;
}

+ 107
- 0
css/xeroc.css View File

@@ -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 */
}

+ 68
- 0
html/bts_staff_hours_template.html View File

@@ -0,0 +1,68 @@
{{#lines}}
<tr>
<td>{{staff_name}}</td>
<td>{{rate_name}}</td>
<td class=sync_detail>
<table class='hours'>
<thead id="p{{staff_id}}">
<th>{{days_1}}</th>
<th>{{days_2}}</th>
<th>{{days_3}}</th>
<th>{{days_4}}</th>
<th>{{days_5}}</th>
<th>{{days_6}}</th>
<th>{{days_7}}</th>
<th>{{days_8}}</th>
<th>{{days_9}}</th>
<th>{{days_10}}</th>
<th>{{days_11}}</th>
<th>{{days_12}}</th>
<th>{{days_13}}</th>
<th>{{days_14}}</th>
</thead>
<tbody>
<tr>
<td class='local week1color' id='a_0'>{{local_1}}</td>
<td class='local week1color' id='a_1'>{{local_2}}</td>
<td class='local week1color' id='a_2'>{{local_3}}</td>
<td class='local week1color' id='a_3'>{{local_4}}</td>
<td class='local week1color' id='a_4'>{{local_5}}</td>
<td class='local week1color' id='a_5'>{{local_6}}</td>
<td class='local week1color' id='a_6'>{{local_7}}</td>
<td class='local week2color' id='a_7'>{{local_8}}</td>
<td class='local week2color' id='a_8'>{{local_9}}</td>
<td class='local week2color' id='a_9'>{{local_10}}</td>
<td class='local week2color' id='a_10'>{{local_11}}</td>
<td class='local week2color' id='a_11'>{{local_12}}</td>
<td class='local week2color' id='a_12'>{{local_13}}</td>
<td class='local week2color' id='a_13'>{{local_14}}</td>
</tr>
<tr>
<td colspan="14">
<div style="text-align: center">To Xero
<span class="ticon ticon-arrow-down"></span>
</div>
</td>
</tr>
<tr>
<td class='xero week1color' id='b_0'>{{xero_1}}</td>
<td class='xero week1color' id='b_1'>{{xero_2}}</td>
<td class='xero week1color' id='b_2'>{{xero_3}}</td>
<td class='xero week1color' id='b_3'>{{xero_4}}</td>
<td class='xero week1color' id='b_4'>{{xero_5}}</td>
<td class='xero week1color' id='b_5'>{{xero_6}}</td>
<td class='xero week1color' id='b_6'>{{xero_7}}</td>
<td class='xero week2color' id='b_7'>{{xero_8}}</td>
<td class='xero week2color' id='b_8'>{{xero_9}}</td>
<td class='xero week2color' id='b_9'>{{xero_10}}</td>
<td class='xero week2color' id='b_10'>{{xero_11}}</td>
<td class='xero week2color' id='b_11'>{{xero_12}}</td>
<td class='xero week2color' id='b_12'>{{xero_13}}</td>
<td class='xero week2color' id='b_13'>{{xero_14}}</td>
</tr>
</tbody>
</table>
</td>
<td style="vertical-align:bottom;">{{Xero_Status}}</td>
</tr>
{{/lines}}

BIN
img/csv.png View File

Before After
Width: 600  |  Height: 600  |  Size: 188KB

BIN
img/wnet.png View File

Before After
Width: 128  |  Height: 128  |  Size: 10KB

BIN
img/xero.png View File

Before After
Width: 128  |  Height: 128  |  Size: 6.1KB

+ 79
- 0
js/xeroc.js View File

@@ -0,0 +1,79 @@
(function ($) {
$(function () {
/*_____________________________________________*/

function test(){
var temp = $('#bts_staff_hours_template').html();
var lines = [];
for (var i=1; i<10; i++){
var data = {
staff_name: 'john',
rate_name : 'some rate name',
staff_id:"abc_"+ i,
};
data.days={};
for (var j =1; j<=14; j++){
data['days_' + j] = j + '/July';
}
lines.push(data);
}
var html = Mustache.render(temp, {lines:lines});
$('#staff').append(html);
}
function datebox(){
$( ".boundary_datepicker" ).datepicker();
$( ".boundary_datepicker" ).datepicker("option", "dateFormat", "yy-mm-dd");
}
function display_hour_lines(response)
{
$('#staff').html();
var temp = $('#bts_staff_hours_template').html();
var html = Mustache.render(temp, response);
$('#staff').append(html);
}
function set_payroll_calendar(cal)
{
$('#cstart').attr('value', cal.start);
$('#cfinish').attr('value', cal.finish);
$('#paydate').attr('value', cal.paydate);
}
function get_timesheet_from_xero(){
$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "get_timesheet_from_xero", // action
sync: false,
}).done(function(response){
set_payroll_calendar(response.payroll_calendar);
console.log("%o", response);
display_hour_lines(response);
}).fail(function(){
console.warn('failed');
}).always(function(){
console.log('completed');
});
}
function sync_timesheet_from_xero(){
$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "get_timesheet_from_xero", // action
sync: true,
}).done(function(response){
set_payroll_calendar(response.payroll_calendar);
console.log("%o", response);
display_hour_lines(response);
}).fail(function(){
console.warn('failed');
}).always(function(){
console.log('completed');
});
}
$('#sync_timesheet').click(function(){
sync_timesheet_from_xero();
});
/*_____________________________________________*/
});
})(jQuery);

+ 213
- 5
ts.php View File

@@ -48,6 +48,7 @@ class AcareOffice{
add_shortcode( 'bts_staff_job_summary', array($this, 'bts_staff_job_summary'));
add_shortcode( 'bts_feedback_card', array($this, 'bts_feedback_card'));
add_shortcode( 'bb_timesheet_canvas', array($this, 'bb_timesheet_canvas'));
add_shortcode( 'bts_staff_hours_template', array($this, 'bts_staff_hours_template'));
//user profile page
@@ -76,6 +77,7 @@ class AcareOffice{
add_action('wp_ajax_client_ack_job', array($this,'client_ack_job' ));
add_action('wp_ajax_nopriv_client_ack_job', array($this,'client_ack_job' ));
add_action('wp_ajax_get_timesheet_from_xero', array($this,'get_timesheet_from_xero' ));
// hook add_rewrite_rules function into rewrite_rules_array
add_filter('rewrite_rules_array', array($this,'my_add_rewrite_rules'));
@@ -363,6 +365,7 @@ class AcareOffice{
$this->register_timesheet_js_css();
$this->register_task_js_css();
$this->register_feedback_card_js_css();
$this->register_xeroc_js_css();
}
private function register_bts_js()
{
@@ -449,6 +452,21 @@ class AcareOffice{
) );
}
private function register_xeroc_js_css(){
global $pagename;
if ($pagename != 'xeroc'){
return;
}
wp_enqueue_style( 'bts_xeroc', plugins_url('css/xeroc.css', __FILE__));
wp_enqueue_script( 'bts_xeroc', plugins_url('js/xeroc.js', __FILE__), array( 'jquery' , 'bts' ));
wp_enqueue_script('mustache', plugins_url('js/mustache.min.js', __FILE__), array('jquery'));
global $wp_scripts;
wp_enqueue_script('jquery-ui-datepicker');
$url = plugins_url('jquery-ui-1.11.4.theme/jquery-ui.min.css', __FILE__);
wp_enqueue_style('jquery-ui-smoothness', $url, false, null);
}
public function sync_users()
{
//dummy sync
@@ -482,6 +500,16 @@ class AcareOffice{
return;
}
public function produce_invoice($args = array(), $assoc_args = array())
{
$users = get_users(array('role' => 'client'));
foreach ($users as $u)
{
$pay = get_user_meta($u->id, 'payment',true);
echo sprintf("%s: %s\n", $u->display_name, $pay);
}
}
private function send_email_with_job_link($staff, $start, $finish)
{
$message = file_get_contents(plugin_dir_path(__FILE__) . "/html/email_job.html");
@@ -522,6 +550,15 @@ class AcareOffice{
return $result;
}
private function get_rate_name_by_id($id)
{
$options = get_option('bts_payitem_earnings_rate');
foreach($options as $o){
if ( $o['EarningsRateID'] == $id )
return sprintf("$%3.2f-%s", $o['RatePerUnit'], $o['Name']);
}
}
public function bts_select_staff($attr){
$result = "<select> \n";
$staff = $this->get_people_by_role('staff');
@@ -569,6 +606,10 @@ class AcareOffice{
{
return file_get_contents(plugin_dir_path(__FILE__) . "/html/timesheet.html");
}
public function bts_staff_hours_template($attr){
return $this->template('bts_staff_hours_template', 'bts_staff_hours_template.html');
}
//generate template based on html file
private function template($id, $file)
{
@@ -772,7 +813,7 @@ class AcareOffice{
$u = get_user_by('login', $staff);
if ($this->is_staff($u)){
$n = new UserJob($staff);
$resp = $n->list_jobs("$start 00:00:00", "$finish 23:59:59");
$resp = $n->list_jobs_by_staff("$start 00:00:00", "$finish 23:59:59");
if ($resp['status']=='success' && $resp['job_count'] >0 ){
$msg = sprintf("Email to <strong>%s</strong> (with job=%d) \n", $u->user_email, $resp['job_count']);
$this->send_email_with_job_link($u, $start, $finish);
@@ -953,13 +994,179 @@ class AcareOffice{
wp_send_json($response);
}
public function get_timesheet_from_xero()
{
check_ajax_referer('acaresydney');
//check if we need sync
$sync = $_POST['sync'];
if ($sync != "true")
$sync = false;
else
$sync = true;
//set up payroll calendar
$pc = $this->xero->get_payroll_calendar();
$start = $pc->getStartDate()->format('Y-m-d');
$finish = new \DateTime($start);
$finish = $finish->modify("+13 days")->format('Y-m-d');
$paydate = $pc->getPaymentDate()->format('Y-m-d');
//prepare response
$response = array(
'status' => 'success',
'payroll_calendar' => array(
'start' => $start,
'finish' => $finish,
'paydate'=> $paydate,
),
);
$xx = new \Biukop\TimeSheet($this->xero->get_xero_handle(), $finish);
$local_ts = $this->create_timesheet_from_db($start, $finish);
if ($sync){
$xx->set_local_timesheet($local_ts);
$xx->save_to_xero();
}
$days=[];
$d = new \DateTime($start);
for ($i=1; $i<=14; $i++){
$days["days_$i"] = $d->format("d/F");
$d->modify("+1 day");
}
$lines=[];
foreach ($local_ts as $staff_login => $details)
{
$item = array(
'staff_name' => $this->get_user_name_by_login ($staff_login),
'staff_id' => $staff_login,
'Xero_Status' => 'Empty',
);
//for local
foreach($details as $rate => $hours){
$item['rate_name'] = $this->get_rate_name_by_id($rate);
for ($i=1; $i<=14; $i++)
{
$item["local_$i"] = $hours[$i-1];
}
}
//for remote
$buddy = $xx->get_buddy_timesheets($staff_login, new \DateTime($start), new \DateTime($finish));
if ( $buddy != NULL )
{
$item['Xero_Status'] = $buddy->getStatus();
$remote_lines = $buddy->getTimesheetLines();
foreach($remote_lines as $rl)
{
if ( $rl->getEarningsRateID() == $rate){
for ($i=1; $i<=14; $i++)
{
$item["xero_$i"] = $rl->getNumberOfUnits()[$i-1];
}
break;//we found it
}
}
}
$item = array_merge($item, $days);
$lines[]=$item;
}
$ts = json_decode(file_get_contents(dirname(__FILE__) . "/sample/timesheets.json"));
$response['ts'] = $ts;
$response['lines'] = $lines;
wp_send_json($response);
}
static public function get_user_name_by_login($login)
{
$user = get_user_by('login', $login);
if ($user->ID !=0 )
return $user->display_name;
else
return "Invalid Name";
}
public function create_timesheet_from_db($start, $finish){
$results = [];
$sql = "SELECT * from $this->table_name WHERE start>='$start 00:00:00' and start<='$finish 23:59:59'";
$rows = $this->db->get_results($sql);
foreach ($rows as $r){
if (!array_key_exists($r->staff, $results)){
$results[$r->staff] = [];
}
if (!array_key_exists($r->rate, $results[$r->staff])){
$results[$r->staff][$r->rate] = [];
for ($i=0; $i<14; $i++){
$results[$r->staff][$r->rate][$i] = 0; //14 days init to 0;
}
}
$idx = $this->convert_date_to_idx($r->start, $start, $finish);
if ($idx >=0 && $idx <=13){
$hours = $this->get_job_hours($r->start, $r->finish);
$results[$r->staff][$r->rate][$idx] += $hours;
//$results[$r->staff][$r->id] = $hours;
//$results[$r->staff][$r->id . '_index'] = $idx;
}else{
$msg = sprintf("ACARE_TS_ERR: found invalid job index for job id=%d, on %s, idx is %d, start=%s, finish=%s\n",
$r->id, date('Y-m-d'), $idx, $start, $finish);
$this->log($msg);
}
}
//wp_send_json($results);
return $results;
}
//convert date (no time) to index, 0 day is $start, 13day is finish, -1 is not found
public function convert_date_to_idx($date, $start, $finish)
{//start, finish format must be yyyy-mm-dd
$idx = -1;
$cur = new \DateTime($date);
$cur->setTime(0,0,0);//clear time;
$s = new \DateTime($start);
$s->setTime(0,0,0);
$f = new \DateTime($finish);
$f->setTime(0,0,0);
if ( $s <= $cur && $cur <=$f ){
$datediff = date_diff($s,$cur);
$idx = $datediff->days;
}
return $idx;
}
private function get_job_hours($start, $finish)
{
$hours = 0;
$s = strtotime($start);
$f = strtotime($finish);
$diff = $f- $s;
$hours = ($diff * 1.0 / 3600); //can be float;
return $hours;
}
public function feedback_url()
{
$users = get_users(array('role'=>'client'));
foreach($users as $u){
echo sprintf("%s:\t https://acaresydney.com.au/feedback_card/%s/\n", $u->display_name, $u->user_login);
echo sprintf("Hi %s:\n\nPlease rate our service, https://acaresydney.com.au/feedback_card/%s/\n\nAcareSydney\n\n", $u->display_name, $u->user_login);
}
}
static public function log($msg){
openlog("ACARE_TS", LOG_PID | LOG_PERROR, LOG_SYSLOG);
//something wrong, we dont touch it, but give some error here
syslog(LOG_WARNING, $msg);
closelog();
}
}

$bb = new AcareOffice();
@@ -968,7 +1175,8 @@ if ( defined( 'WP_CLI' ) && WP_CLI ) {
\WP_CLI::add_command( 'sync_users', array($bb, 'sync_user_cli'));
\WP_CLI::add_command( 'email_jobs', array($bb, 'email_jobs'));
\WP_CLI::add_command( 'feedback_url', array($bb, 'feedback_url'));
\WP_CLI::add_command( 'produce_invoice', array($bb, 'produce_invoice'));
}
//$bb->class_loader();
//$bb->list_job_by_staff();
//$idx = $bb->convert_date_to_idx("2019-07-02 14:30:00", "2019-07-01", "2019-07-02");
//wp_send_json($idx);
//$bb->create_timesheet_from_db("2019-07-01", "2019-07-14");

Loading…
Cancel
Save