|
- <?php
-
- namespace Biukop;
-
- class XeroOauth2Sync
- {
- private $oauth2;
- private $clientContactGroupID="48646f3d-cf5e-4fea-8c8b-5812bd540e1b";
- private $minimum_sync_interval_in_seconds=600;
- public function __construct($oauth2)
- {
- $this->oauth2 = $oauth2;
- }
-
- /*
- * Sync users from Xero to WordPress
- *
- * Contact group: 48646f3d-cf5e-4fea-8c8b-5812bd540e1b "Clients -need carer"
- * Employees: All with "web-employee" or "skip_office_sync"
- *
- * Since Xero has API call rate limits 60 calls/ minute, we can only sync some of them
- *
- * Assuming sync_users were called at every 30 minutes, each time we retrieve
- * all clients, all employees and tries to update them;
- *
- *
- * Minimum API call quota cost,for each sync
- * getContacts retrieves all contacts 500+
- * getContactGroups retrieves all clients around 100
- * getEmployees need multiple request, each request get 100 employee at most.
- *
- * Each time (every sync) we use at least 4 API calls
- *
- * We then compare the lastsync user_meta value with the update time of each user
- * if lastsync is older than last update, then we do updates
- *
- */
- public function sync_users($mininterval=600, $employeeonly=false, $clientsonly=false){
- $this->usage();
- $this->minimum_sync_interval_in_seconds = $mininterval;
- $msg="Sync users with minimum interval set to $mininterval \n";
- $this->logConsole($msg);
-
- try{
- $this->sync_clients();
- $this->sync_employees();
- }catch(\XeroAPI\XeroPHP\ApiException $e){
- $msg= "Xero API exceiption encountered during Sync: " . $e->getMessage() ." true " . print_r($e,true);
- $this->logConsole($msg);
- }
- }
-
- private function get_last_sync($userid){
- $lastsync = get_user_meta($userid, 'lastsync', true);
- return (int)($lastsync);
- }
- private function mark_user_updated($userid, $timestamp){
- update_user_meta($userid, 'lastsync', $timestamp);
- }
-
- private function sync_clients(){
- $allClients = $this->oauth2->getClients(); // by calling oauth2, the cache HTML is updated.
- foreach ($allClients as $c) {
- $this->update_or_create_clients($c);
- }
- }
-
- private function sync_employees(){
- $allEmployees = $this->oauth2->getEmployees(); // by calling oauth2, the cache HTML is updated.
- $to_update=[];
- $to_test=[];
- $api = $this->oauth2->get_payroll_au_instance();
- foreach ($allEmployees as $e) {
- switch($e->getEmployeeGroupName()){
- case "Web-Employee":
- $this->update_or_create_employees($e);
- break;
- case "skip_office_sync":
- $this->update_or_create_employees($e);
- // $e->setEmployeeGroupName("Web-Employee");
- // $to_update[]= $e;
- // if ( count($to_test) <= 2 ){
- // $to_test[] = $e;
- // }
- break;
- default:
- // other employee such as duplicate we just bypass them
- ;
- }
- }
- }
-
- private function update_or_create_clients($contact) {
- $login = $contact->getContactId();
- if ( trim( $login) === "" ) {
- return; //invalid contact;
- }
- $user = get_user_by('login', $login);
- if ($user === false){
- $this->add_new_contact($contact);
- }else{
- $this->update_existing_contact($contact);
- }
- }
-
- private function update_or_create_employees($employee) {
- $login = $employee->getEmployeeID();
- if ( trim( $login) === "" ) {
- return; //invalid contact;
- }
- switch($employee->getEmployeeGroupName()){
- case "Web-Employee":
- case "skip_office_sync":
- break;
- default:
- // other employee such as duplicate we just bypass them
- return;
- }
- $user = get_user_by('login', $login);
- if ($user === false){
- $this->add_new_staff($employee);
- }else{
- $this->update_existing_staff($employee);
- }
- }
-
- public function getClients() {
- $contact_group_id = $this->clientContactGroupID;
- $apiAcc = $this->oauth2->get_accounting_instance();
- $result = $apiAcc->getContactGroupWithHttpInfo($this->oauth2->getTenantId(), $contact_group_id);
- $this->logConsole(print_r($result,true));
- $this->logConsole(print_r($result[2],true));
- $cg = $result[0]->getContactGroups();
- $allClients = $cg[0]->getContacts();
-
- $ifModifiedSince = new \DateTime();
- $recent = new \DateInterval("P30000D"); // 30,000 days, means everything
- $ifModifiedSince->sub($recent);
- $where=null;
- $order="UpdatedDateUTC DESC";
-
- $allContacts = $apiAcc->getContacts($this->oauth2->getTenantId(), $ifModifiedSince, $where, $order);
- $ret = [];
- foreach ( $allContacts as $ac ) {
- //search from within the group
- $found = false;
- $id = $ac->getContactID();
- foreach ($allClients as $client) {
- $clientID = $client->getContactID();
- if ( $clientID == $id ) {
- $found = true;
- break;
- }
- }
-
- if ( $found ) {
- $ret[] = $ac;
- }
-
- }
- return $ret;
- }
-
- public function getEmployees() {
- $api = $this->oauth2->get_payroll_au_instance();
- $xeroTenantId = $this->oauth2->xeroTenantId;
- //$xeroTenantId = "e23fd416-3b66-43e9-b908-97fbefa24eb8"; // demo company;
- //$xeroTenantId = "4e2521ae-83e6-4895-aa90-b20aa0825ce1"; // Acaresydney ;
-
- $ifModifiedSince = null;// date("M d Y H:i:s", strtotime("-30 days"));
- $where = "Status==\"ACTIVE\"";
- $order = "UpdatedDateUTC DESC"; // "null; // "EmailAddress%20DESC";
- $page = 1;
-
- $employees=[];
- do {
- $result = $api->getEmployees($xeroTenantId,$ifModifiedSince,$where,$order,$page);
- $thisPage = $result->getEmployees();
- $employees = array_merge($employees, $thisPage);
- $page++;
- }while (count($thisPage) == 100);
-
- return $employees;
- }
-
- public function get_client_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 add_new_contact($contact){
- $login = $contact->getContactId();
- $user = get_user_by('login', $login);
- if ($user === false){
- $msg = sprintf("ADD Client name=[%s] {%s} \n", $contact->getName(), $contact->getContactId());
- $this->logConsole($msg);
-
- $args = $this->xero_contact_profile($contact);
- $id = wp_insert_user($args);
-
- if (! $id instanceof \WP_Error){
- $user = get_user_by('ID', $id);
- update_user_meta($user->ID, 'address', $args['address']);
- update_user_meta($user->ID, 'account', $args['account']);
- $this->mark_user_updated($login, $contact->getUpdatedDateUtcAsDate()->format('U'));
- }else{
- $msg = "==(Add Client failed)==";
- $this->logConsole($msg);
- $msg = sprintf("ADD Client name=[%s] {%s} Failed\n", $contact->getName(), $contact->getContactId());
- error_log("ACARE add client failed: $msg");
- }
- }
- }
-
- private function update_existing_contact($contact){
- $login = $contact->getContactID();
- $user = get_user_by('login', $login);
- if ($user !== false)
- {//update user - must be existing user;
- if (! $this->user_requires_update($user, $contact)){
- $this->logConsole("skip update client (lastSync is up-to-date) : " . $contact->getName() . "\n");
- return;
- }
- $args = $this->xero_contact_profile($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_user_updated($user->ID, $contact->getUpdatedDateUtcAsDate()->format('U'));
-
- }
- }
-
- private function xero_contact_profile($c){
- return [
- '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_client_post_address($c),
- 'role' => 'client',
- ];
- }
-
- private function user_requires_update($user, $contact) {
-
- $lastSync = $this->get_last_sync($user->ID);
- $updated = $contact->getUpdatedDateUtcAsDate()->format('U');;
-
- return $lastSync < $updated;
- }
-
- private function add_new_staff($employee)
- {
- $login = $employee->getEmployeeID();
- $user = get_user_by('login', $login);
- if ($user === false){
- $msg = sprintf("ADD employee name=[%s %s] {%s} \n",
- $employee->getFirstName(),
- $employee->getLastName(),
- $employee->getEmployeeID());
- $this->logConsole($msg);
-
- $args = $this->xero_employee_profile($employee);
- $this->logConsole(print_r($args, true));
- $id = wp_insert_user($args);
- $this->logConsole(print_r($id, true));
- if (! $id instanceof \WP_Error){
- $user = get_user_by('ID', $id);
- update_user_meta($user->ID, 'mobile', $args['mobile']);
- update_user_meta($user->ID, 'address', $args['address']);
- $this->mark_user_updated($user->ID, $employee->getUpdatedDateUtcAsDate()->format('U'));
- }else{
- $msg = "==(Add staff failed)==";
- $this->logConsole($msg);
-
- $msg = sprintf("ADD employee name=[%s %s] {%s} Failed\n",
- $employee->getFirstName(),
- $employee->getLastName(),
- $employee->getEmployeeID());
- error_log("ACARE add employee failed: $msg");
- }
- }
- }
-
- private function update_existing_staff($employee)
- {
- $login = $employee->getEmployeeID();
- $user = get_user_by('login', $login);
- if ($this->user_requires_update($user, $employee)){
- $this->logConsole("skip update EMPLOYEE (lastSync is up-to-date) : " .
- $employee->getFirstName() . " " . $employee->getLastName() . "\n");
- return;
- }
- if ($user != false) {
- $args = $this->xero_employee_profile($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_user_updated($user->ID, $employee->getUpdatedDateUtcAsDate()->format('U'));
- }
- }
-
- private function xero_employee_profile($e){
- $args = [
- 'user_login' => $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_home_address($e),
- 'role' => 'staff',
- ];
- return $args;
- }
-
- public function get_employee_home_address($e){
- // "HomeAddress": {
- // "AddressLine1": "16 Quist Avenue",
- // "City": "Lurnea",
- // "Region": "NSW",
- // "PostalCode": "2170",
- // "Country": "AUSTRALIA"
- // },
- $addr = "";
- $home = $e->getHomeAddress();
- if ( $home == null ) {
- return "";
- }
- $addr .= $home->getAddressLine1() .",";
- $addr .= $home->getAddressLine2() .",";
- $addr .= $home->getCity() . ",";
- $addr .= $home->getRegion() . " ";
- $addr .= $home->getCountry() ." ";
- $addr .= $home->getPostalCode();
- return $addr;
- }
-
- private function usage(){
- $msg = "_____________________________________________\n";
- $msg .= "run this command at public_html/, where wp-config.php exist \n";
- $msg .= "wp sync_users \n";
- $msg .= "but it may hit XERO rate limit, 60call/sec, 5000/day \n";
- $msg .= "---------------------------------------------\n";
- $this->logConsole($msg);
- }
-
- private function logConsole($str){
- //if is commandline
- if ( defined( 'WP_CLI' ) && WP_CLI ) {
- echo $str;
- }
- }
- }
|