[ 'callback' => 'http://acaresydney.com.au/', 'consumer_key' => 'G6AJIRWTH0X3C5SVS3ETZXNFCMDNGG', 'consumer_secret' => 'LP0PTSBCJLBB4CGYYKOHDXYF2NWXWD', 'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem', ], ); return $config; } private function office_config(){ $office_config = [ 'xero' => [ // 'payroll_version' =>'1.9', ], 'curl' => [ CURLOPT_USERAGENT =>'AcareSydneyWebOffice', ], 'oauth' => [ 'callback' => 'http://acaresydney.com.au/', 'consumer_key' => 'JE4LWKCJ6NHED30RFZWCT7WQYTS8JD', 'consumer_secret' => 'JXVZAZWKGM7MLUZSVIMK7ZSJE9GNYQ', 'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem', ], ]; return $office_config; } public function __construct(){ $this->xero = new PrivateApplication($this->office_config()); } public function getClients($contact_group_id){ $xero = $this->xero; $cg = $xero->loadByGUID("Accounting\\ContactGroup", $contact_group_id); $contacts = $cg->getContacts(); return $contacts; } public function getContact($id){ $user = $this->xero->loadByGUID("Accounting\\Contact",$id); return $user; } public function getEmployees(){ $employees = $this->xero->load("PayrollAU\\Employee") ->where('EmployeeGroupName="Web-Employee"') ->execute(); return $employees; } public function getEmployee($id){ $employee = $this->xero->loadByGUID("PayrollAU\\Employee",$id); return $employee; } // //sync users to wordpress system //does not work for too many users or employees public function sync_users($mininterval, $employeeonly, $clientsonly){ $this->usage(); $this->minimum_sync_interval_in_seconds = $mininterval; $msg="Sync users with minimum interval set to $mininterval \n"; $this->logConsole($msg); try{ if ($clientsonly){ $this->sync_clients(); }else if ($employeeonly){ $this->sync_employees(); }else{ $this->sync_clients(); $this->sync_employees(); } }catch(RateLimitExceededException $e){ $msg= "Xero API rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n"; $this->logConsole($msg); }catch(NotFoundException $e){ $msg= "Xero API resource not found rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n"; $this->logConsole($msg); } } private function sync_clients(){ $contacts = $this->getClients($this->clientgroup); foreach ($contacts as $c){ $msg = sprintf("SYNC Client name=[%s] {%s} \n", $c->getName(), $c->getContactID()); $this->logConsole($msg); $this->ensure_contact_exists($c); } } private function sync_employees(){ $employees = $this->getEmployees(); foreach ( $employees as $e){ $msg = sprintf("SYNC employee name=[%s %s] {%s} \n", $e->getFirstName(), $e->getLastName(), $e->getEmployeeID()); $this->logConsole($msg); // if ($e->getEmployeeID() != '3e8c2e62-8e28-4b68-ae98-9ef1d76188c4') // continue; $this->ensure_staff_exists($e); } } private function ensure_contact_exists($contact){ $login = $contact->getContactID(); $user = get_user_by('login', $login); if ($user === false){ $xero_contact = $this->getContact($login); $args = $this->xero_contact_profile($xero_contact); $id = wp_insert_user($args); $user = get_user_by('ID', $id); update_user_meta($user->ID, 'address', $args['address']); update_user_meta($user->ID, 'account', $args['account']); }else{//update user if ($this->is_too_close_to_sync($user)){ return; } $xero_contact = $this->getContact($login); $args = $this->xero_contact_profile($xero_contact); $args['ID'] = $user->ID; unset($args['user_pass']); //we don't change password wp_update_user($args); update_user_meta($user->ID, 'address', $args['address']); update_user_meta($user->ID, 'account', $args['account']); } $this->mark_updated($user->ID); } private function xero_contact_profile($c){ $args = [ 'user_login' => $username = $c->getContactID(), 'user_pass' => md5(uniqid(rand() + time(), true)), 'display_name' =>$c->getName(), 'user_email' => $c->getEmailAddress(), 'first_name' => $c->getFirstName(), 'last_name' => $c->getLastName(), 'nickname' => $c->getName(), 'account' => $c->getAccountNumber(), 'address'=> $this->get_post_address($c), 'role' => 'client', ]; return $args; } private function get_post_address($client){ $result = ""; $addr = $this->get_client_address_by_type($client, 'POBOX'); if ( $addr != false){ if ($addr->getAddressLine1() != ""){ $result .= $addr->getAddressLine1() . ";"; } if ($addr->getAddressLine2() != ""){ $result .= $addr->getAddressLine2() . ";"; } if ($addr->getAddressLine3() != ""){ $result .= $addr->getAddressLine3() . ";"; } if ($addr->getAddressLine4() != ""){ $result .= $addr->getAddressLine4() . ";"; } if ($addr->getCity() != ""){ $result .= $addr->getCity() . ";"; } if ($addr->getPostalCode() != ""){ $result .= $addr->getPostalCode() . ";"; } } echo "result for client is " . $result . "\n"; return $result; } private function get_client_address_by_type($client, $t){ $addr = false; foreach( $client->getAddresses() as $a){ if( $a->getAddressType() == $t){ $addr = $a; break; } } return $addr; } private function ensure_staff_exists($employee) { $login = $employee->getEmployeeID(); $user = get_user_by('login', $login); if ($user === false){ echo "add new \n"; $xero_employee = $this->getEmployee($login); $args = $this->xero_employee_profile($xero_employee); $id = wp_insert_user($args); $user = get_user_by('ID', $id); update_user_meta($user->ID, 'mobile', $args['mobile']); update_user_meta($user->ID, 'address', $args['address']); }else{ if ($this->is_too_close_to_sync($user)){ return; } $xero_employee = $this->getEmployee($login); $args = $this->xero_employee_profile($xero_employee); $args['ID'] = $user->ID; unset($args['user_pass']); wp_update_user($args); update_user_meta($user->ID, 'mobile', $args['mobile']); update_user_meta($user->ID, 'address', $args['address']); } $this->mark_updated($user->ID); } private function xero_employee_profile($e){ $args = [ 'user_login' => $username = $e->getEmployeeID(), 'user_pass' => md5(uniqid(rand() + time(), true)), 'display_name' =>$e->getFirstName() . " " . $e->getLastName(), 'user_email' => $e->getEmail(), 'first_name' => $e->getFirstName(), 'last_name' => $e->getLastName(), 'nickname' => $e->getFirstName(), 'mobile' => $e->getMobile(), 'address'=> $this->get_employee_address($e), 'role' => 'staff', ]; return $args; } private function get_employee_address($e){ // "HomeAddress": { // "AddressLine1": "16 Quist Avenue", // "City": "Lurnea", // "Region": "NSW", // "PostalCode": "2170", // "Country": "AUSTRALIA" // }, $addr = ""; $home = $e->getHomeAddress(); $addr .= $home->getAddressLine1() .","; $addr .= $home->getAddressLine2() .","; $addr .= $home->getCity() . ","; $addr .= $home->getRegion() . " "; $addr .= $home->getCountry() ." "; $addr .= $home->getPostalCode(); return $addr; } private function mark_updated($userid){ update_user_meta($userid, 'lastsync', time()); } private function get_last_sync($userid){ $lastsync = get_user_meta($userid, 'lastsync', true); return (int)($lastsync); } private function is_too_close_to_sync($user){ $userid = $user->ID; $lastsync = $this->get_last_sync($user->ID); $now = time(); $diff = $now - (int) $lastsync; if ($diff < $this->minimum_sync_interval_in_seconds){ $msg = sprintf("\tSKIP userid(%d),login=%s,display_name=%s,(lastsync=%d secs ago, mininterval=%d) \n", $user->ID, $user->user_login, $user->display_name, $diff, $this->minimum_sync_interval_in_seconds); $this->logConsole($msg); return true; } return false; } private function logConsole($str){ //if is commandline if ( defined( 'WP_CLI' ) && WP_CLI ) { echo $str; } } private function usage(){ $msg = "_____________________________________________\n"; $msg .= "run this command at public_html/, where wp-config.php exist \n"; $msg .= "wp sync_users --mininterval=6000 \n"; $msg .= "6000 means those users synced within 6000 seconds will be bypassed \n"; $msg .= "to sync everything \n"; $msg .= "wp sync_users --mininterval=0 [--clientsonly] [--employeeonly]\n"; $msg .= "but it may hit XERO rate limit, 60call/sec, 5000/day \n"; $msg .= "---------------------------------------------\n"; $this->logConsole($msg); } /* sync payitems to wp options */ public function init_wp(){ $this->sync_payitem(); } private function sync_payitem(){ if ($this->too_close_to_sync_payitem()){ return; } $payitems = $this->xero->load('PayrollAU\\PayItem')->execute(); $payitem_options = array(); foreach ($payitems[0]->getEarningsRates() as $e){ // "EarningsRateID": "34e17d08-237a-4ae2-8115-375d1ff8a9ed", // "Name": "Overtime Hours (exempt from super)", // "EarningsType": "OVERTIMEEARNINGS", // "RateType": "MULTIPLE", // "AccountCode": "477", // "Multiplier": 1.5, // "IsExemptFromTax": true, // "IsExemptFromSuper": true, // "AccrueLeave": false, // "IsReportableAsW1": true, // "UpdatedDateUTC": "2019-03-16T13:18:19+00:00", // "CurrentRecord": false if ($e->getCurrentRecord() == "true"){ $payitem_options[]= array( 'EarningsRateID' => $e->getEarningsRateID(), 'Name'=> $e->getName(), 'EarningsType'=> $e->getEarningstype(), 'RatePerUnit' => $e->getRatePerUnit(), 'RateType' => $e->getRateType(), 'AccountCode' => $e->getAccountCode(), "Multiplier"=> $e->getMultiplier(), "IsExemptFromTax" => $e->getIsExemptFromTax(), "IsExemptFromSuper"=> $e->getIsExemptFromSuper(), "AccrueLeave" => $e->getAccrueLeave(), ); } } update_option('bts_payitem_earnings_rate', $payitem_options); update_option('bts_payitem_last_sync', time()); } private function too_close_to_sync_payitem(){ $lastsync = get_option('bts_payitem_last_sync', 0); $now = time(); $diff = $now - (int) $lastsync; return $diff < $this->minimum_sync_interval_in_seconds; //default 10 minutes } }