timesheet source code
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

355 lines
13KB

  1. <?php
  2. namespace Biukop;
  3. use \XeroPHP\Application\PrivateApplication;
  4. use \XeroPHP\Remote\Exception\RateLimitExceededException;
  5. use \XeroPHP\Remote\Exception\NotFoundException;
  6. class Xero {
  7. private $xero;
  8. private $clientgroup="48646f3d-cf5e-4fea-8c8b-5812bd540e1b";
  9. private $minimum_sync_interval_in_seconds = 600;
  10. private function default_config(){
  11. $config = array(
  12. 'oauth' => [
  13. 'callback' => 'http://acaresydney.com.au/',
  14. 'consumer_key' => 'G6AJIRWTH0X3C5SVS3ETZXNFCMDNGG',
  15. 'consumer_secret' => 'LP0PTSBCJLBB4CGYYKOHDXYF2NWXWD',
  16. 'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem',
  17. ],
  18. );
  19. return $config;
  20. }
  21. private function office_config(){
  22. $office_config = [
  23. 'xero' => [
  24. // 'payroll_version' =>'1.9',
  25. ],
  26. 'curl' => [
  27. CURLOPT_USERAGENT =>'AcareSydneyWebOffice',
  28. ],
  29. 'oauth' => [
  30. 'callback' => 'http://acaresydney.com.au/',
  31. 'consumer_key' => 'JE4LWKCJ6NHED30RFZWCT7WQYTS8JD',
  32. 'consumer_secret' => 'JXVZAZWKGM7MLUZSVIMK7ZSJE9GNYQ',
  33. 'rsa_private_key' => 'file://' . dirname(__FILE__) . '/keys/privatekey.pem',
  34. ],
  35. ];
  36. return $office_config;
  37. }
  38. public function __construct(){
  39. $this->xero = new PrivateApplication($this->office_config());
  40. }
  41. public function getClients($contact_group_id){
  42. $xero = $this->xero;
  43. $cg = $xero->loadByGUID("Accounting\\ContactGroup", $contact_group_id);
  44. $contacts = $cg->getContacts();
  45. return $contacts;
  46. }
  47. public function getContact($id){
  48. $user = $this->xero->loadByGUID("Accounting\\Contact",$id);
  49. return $user;
  50. }
  51. public function getEmployees(){
  52. $employees = $this->xero->load("PayrollAU\\Employee")
  53. ->where('EmployeeGroupName="Web-Employee"')
  54. ->execute();
  55. return $employees;
  56. }
  57. public function getEmployee($id){
  58. $employee = $this->xero->loadByGUID("PayrollAU\\Employee",$id);
  59. return $employee;
  60. }
  61. //
  62. //sync users to wordpress system
  63. //does not work for too many users or employees
  64. public function sync_users($mininterval, $employeeonly, $clientsonly){
  65. $this->usage();
  66. $this->minimum_sync_interval_in_seconds = $mininterval;
  67. $msg="Sync users with minimum interval set to $mininterval \n";
  68. $this->logConsole($msg);
  69. try{
  70. if ($clientsonly){
  71. $this->sync_clients();
  72. }else if ($employeeonly){
  73. $this->sync_employees();
  74. }else{
  75. $this->sync_clients();
  76. $this->sync_employees();
  77. }
  78. }catch(RateLimitExceededException $e){
  79. $msg= "Xero API rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n";
  80. $this->logConsole($msg);
  81. }catch(NotFoundException $e){
  82. $msg= "Xero API resource not found rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n";
  83. $this->logConsole($msg);
  84. }
  85. }
  86. private function sync_clients(){
  87. $contacts = $this->getClients($this->clientgroup);
  88. foreach ($contacts as $c){
  89. $msg = sprintf("SYNC Client name=[%s] {%s} \n", $c->getName(), $c->getContactID());
  90. $this->logConsole($msg);
  91. $this->ensure_contact_exists($c);
  92. }
  93. }
  94. private function sync_employees(){
  95. $employees = $this->getEmployees();
  96. foreach ( $employees as $e){
  97. $msg = sprintf("SYNC employee name=[%s %s] {%s} \n", $e->getFirstName(), $e->getLastName(), $e->getEmployeeID());
  98. $this->logConsole($msg);
  99. if ($e->getEmployeeID() != '3e8c2e62-8e28-4b68-ae98-9ef1d76188c4')
  100. continue;
  101. $this->ensure_staff_exists($e);
  102. }
  103. }
  104. private function ensure_contact_exists($contact){
  105. $login = $contact->getContactID();
  106. $user = get_user_by('login', $login);
  107. if ($user === false){
  108. $xero_contact = $this->getContact($login);
  109. $args = $this->xero_contact_profile($xero_contact);
  110. $id = wp_insert_user($args);
  111. $user = get_user_by('ID', $id);
  112. update_user_meta($user->ID, 'address', $args['address']);
  113. update_user_meta($user->ID, 'account', $args['account']);
  114. }else{//update user
  115. if ($this->is_too_close_to_sync($user)){
  116. return;
  117. }
  118. $xero_contact = $this->getContact($login);
  119. $args = $this->xero_contact_profile($xero_contact);
  120. $args['ID'] = $user->ID;
  121. unset($args['user_pass']); //we don't change password
  122. wp_update_user($args);
  123. update_user_meta($user->ID, 'address', $args['address']);
  124. update_user_meta($user->ID, 'account', $args['account']);
  125. }
  126. $this->mark_updated($user->ID);
  127. }
  128. private function xero_contact_profile($c){
  129. $args = [
  130. 'user_login' => $username = $c->getContactID(),
  131. 'user_pass' => md5(uniqid(rand() + time(), true)),
  132. 'display_name' =>$c->getName(),
  133. 'user_email' => $c->getEmailAddress(),
  134. 'first_name' => $c->getFirstName(),
  135. 'last_name' => $c->getLastName(),
  136. 'nickname' => $c->getName(),
  137. 'account' => $c->getAccountNumber(),
  138. 'address'=> $this->get_post_address($c),
  139. 'role' => 'client',
  140. ];
  141. return $args;
  142. }
  143. private function get_post_address($client){
  144. $result = "";
  145. $addr = $this->get_client_address_by_type($client, 'POBOX');
  146. if ( $addr != false){
  147. if ($addr->getAddressLine1() != ""){
  148. $result .= $addr->getAddressLine1() . ";";
  149. }
  150. if ($addr->getAddressLine2() != ""){
  151. $result .= $addr->getAddressLine2() . ";";
  152. }
  153. if ($addr->getAddressLine3() != ""){
  154. $result .= $addr->getAddressLine3() . ";";
  155. }
  156. if ($addr->getAddressLine4() != ""){
  157. $result .= $addr->getAddressLine4() . ";";
  158. }
  159. if ($addr->getCity() != ""){
  160. $result .= $addr->getCity() . ";";
  161. }
  162. if ($addr->getPostalCode() != ""){
  163. $result .= $addr->getPostalCode() . ";";
  164. }
  165. }
  166. echo "result for client is " . $result . "\n";
  167. return $result;
  168. }
  169. private function get_client_address_by_type($client, $t){
  170. $addr = false;
  171. foreach( $client->getAddresses() as $a){
  172. if( $a->getAddressType() == $t){
  173. $addr = $a;
  174. break;
  175. }
  176. }
  177. return $addr;
  178. }
  179. private function ensure_staff_exists($employee)
  180. {
  181. $login = $employee->getEmployeeID();
  182. $user = get_user_by('login', $login);
  183. if ($user === false){
  184. echo "add new \n";
  185. $xero_employee = $this->getEmployee($login);
  186. $args = $this->xero_employee_profile($xero_employee);
  187. $id = wp_insert_user($args);
  188. $user = get_user_by('ID', $id);
  189. update_user_meta($user->ID, 'mobile', $args['mobile']);
  190. update_user_meta($user->ID, 'address', $args['address']);
  191. }else{
  192. if ($this->is_too_close_to_sync($user)){
  193. return;
  194. }
  195. echo "i update existing $user->user_login $user->display_name\n";
  196. $xero_employee = $this->getEmployee($login);
  197. $args = $this->xero_employee_profile($xero_employee);
  198. $args['ID'] = $user->ID;
  199. unset($args['user_pass']);
  200. var_dump($args);
  201. wp_update_user($args);
  202. update_user_meta($user->ID, 'mobile', $args['mobile']);
  203. update_user_meta($user->ID, 'address', $args['address']);
  204. }
  205. $this->mark_updated($user->ID);
  206. }
  207. private function xero_employee_profile($e){
  208. $args = [
  209. 'user_login' => $username = $e->getEmployeeID(),
  210. 'user_pass' => md5(uniqid(rand() + time(), true)),
  211. 'display_name' =>$e->getFirstName() . " " . $e->getLastName(),
  212. 'user_email' => $e->getEmail(),
  213. 'first_name' => $e->getFirstName(),
  214. 'last_name' => $e->getLastName(),
  215. 'nickname' => $e->getFirstName(),
  216. 'mobile' => $e->getMobile(),
  217. 'address'=> $this->get_employee_address($e),
  218. 'role' => 'staff',
  219. ];
  220. return $args;
  221. }
  222. private function get_employee_address($e){
  223. // "HomeAddress": {
  224. // "AddressLine1": "16 Quist Avenue",
  225. // "City": "Lurnea",
  226. // "Region": "NSW",
  227. // "PostalCode": "2170",
  228. // "Country": "AUSTRALIA"
  229. // },
  230. $addr = "";
  231. $home = $e->getHomeAddress();
  232. $addr .= $home->getAddressLine1() .",";
  233. $addr .= $home->getAddressLine2() .",";
  234. $addr .= $home->getCity() . ",";
  235. $addr .= $home->getRegion() . " ";
  236. $addr .= $home->getCountry() ." ";
  237. $addr .= $home->getPostalCode();
  238. return $addr;
  239. }
  240. private function mark_updated($userid){
  241. update_user_meta($userid, 'lastsync', time());
  242. }
  243. private function get_last_sync($userid){
  244. $lastsync = get_user_meta($userid, 'lastsync', true);
  245. return (int)($lastsync);
  246. }
  247. private function is_too_close_to_sync($user){
  248. $userid = $user->ID;
  249. $lastsync = $this->get_last_sync($user->ID);
  250. $now = time();
  251. $diff = $now - (int) $lastsync;
  252. if ($diff < $this->minimum_sync_interval_in_seconds){
  253. $msg = sprintf("\tSKIP userid(%d),login=%s,display_name=%s,(lastsync=%d secs ago, mininterval=%d) \n",
  254. $user->ID, $user->user_login, $user->display_name, $diff, $this->minimum_sync_interval_in_seconds);
  255. $this->logConsole($msg);
  256. return true;
  257. }
  258. return false;
  259. }
  260. private function logConsole($str){
  261. //if is commandline
  262. if ( defined( 'WP_CLI' ) && WP_CLI ) {
  263. echo $str;
  264. }
  265. }
  266. private function usage(){
  267. $msg = "_____________________________________________\n";
  268. $msg .= "run this command at public_html/, where wp-config.php exist \n";
  269. $msg .= "wp sync_users --mininterval=6000 \n";
  270. $msg .= "6000 means those users synced within 6000 seconds will be bypassed \n";
  271. $msg .= "to sync everything \n";
  272. $msg .= "wp sync_users --mininterval=0 [--clientsonly] [--employeeonly]\n";
  273. $msg .= "but it may hit XERO rate limit, 60call/sec, 5000/day \n";
  274. $msg .= "---------------------------------------------\n";
  275. $this->logConsole($msg);
  276. }
  277. /* sync payitems to wp options */
  278. public function init_wp(){
  279. $this->sync_payitem();
  280. }
  281. private function sync_payitem(){
  282. if ($this->too_close_to_sync_payitem()){
  283. return;
  284. }
  285. $payitems = $this->xero->load('PayrollAU\\PayItem')->execute();
  286. $payitem_options = array();
  287. foreach ($payitems[0]->getEarningsRates() as $e){
  288. // "EarningsRateID": "34e17d08-237a-4ae2-8115-375d1ff8a9ed",
  289. // "Name": "Overtime Hours (exempt from super)",
  290. // "EarningsType": "OVERTIMEEARNINGS",
  291. // "RateType": "MULTIPLE",
  292. // "AccountCode": "477",
  293. // "Multiplier": 1.5,
  294. // "IsExemptFromTax": true,
  295. // "IsExemptFromSuper": true,
  296. // "AccrueLeave": false,
  297. // "IsReportableAsW1": true,
  298. // "UpdatedDateUTC": "2019-03-16T13:18:19+00:00",
  299. // "CurrentRecord": false
  300. if ($e->getCurrentRecord() == "true"){
  301. $payitem_options[]= array(
  302. 'EarningsRateID' => $e->getEarningsRateID(),
  303. 'Name'=> $e->getName(),
  304. 'EarningsType'=> $e->getEarningstype(),
  305. 'RatePerUnit' => $e->getRatePerUnit(),
  306. 'RateType' => $e->getRateType(),
  307. 'AccountCode' => $e->getAccountCode(),
  308. "Multiplier"=> $e->getMultiplier(),
  309. "IsExemptFromTax" => $e->getIsExemptFromTax(),
  310. "IsExemptFromSuper"=> $e->getIsExemptFromSuper(),
  311. "AccrueLeave" => $e->getAccrueLeave(),
  312. );
  313. }
  314. }
  315. update_option('bts_payitem_earnings_rate', $payitem_options);
  316. update_option('bts_payitem_last_sync', time());
  317. }
  318. private function too_close_to_sync_payitem(){
  319. $lastsync = get_option('bts_payitem_last_sync', 0);
  320. $now = time();
  321. $diff = $now - (int) $lastsync;
  322. return $diff < $this->minimum_sync_interval_in_seconds; //default 10 minutes
  323. }
  324. }