timesheet source code
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

712 rindas
27KB

  1. <?php
  2. /* xero integration oauth 2 */
  3. /* required by XeroOauth1 in 2021 */
  4. namespace Biukop;
  5. require_once(dirname(__FILE__) . '/vendor/autoload.php');
  6. // require_once(ABSPATH . 'wp-includes/pluggable.php');
  7. require_once(dirname(__FILE__) . '/Storage.php');
  8. use \Carbon_Fields\Container;
  9. use \Carbon_Fields\Field;
  10. use \Carbon_Fields\Carbon_Fields;
  11. use phpDocumentor\Reflection\DocBlock\Tags\Method;
  12. class XeroOAuth2
  13. {
  14. private $office; // parent
  15. private $clientID = '83CC79EEC6A54B4E8C2CA7AD61D1BF69';
  16. private $clientSecret = 'axgKF-Ri60D89conDFhqZsi1wu7uLdQFGvMpino9nI-nfO3f';
  17. private $clientContactGroupID="48646f3d-cf5e-4fea-8c8b-5812bd540e1b";
  18. public $provider;
  19. public $options = [
  20. 'scope' => ['openid email profile offline_access assets projects accounting.settings accounting.transactions accounting.contacts accounting.journals.read accounting.reports.read accounting.attachments payroll.employees payroll.payruns payroll.payslip payroll.timesheets payroll.settings files'],
  21. 'scope1' => [
  22. 'openid',
  23. 'email',
  24. 'profile',
  25. 'offline_access',
  26. 'assets',
  27. 'projects',
  28. 'accounting.settings',
  29. 'accounting.transactions',
  30. 'accounting.contacts',
  31. 'accounting.journals.read',
  32. 'accounting.reports.read',
  33. 'accounting.attachments',
  34. 'payroll.employees',
  35. 'payroll.payruns',
  36. 'payroll.payslip',
  37. 'payroll.timesheets',
  38. 'payroll.settings'
  39. ]
  40. ];
  41. public $storage;
  42. public $config;
  43. public $apiAccountingInstance; //accounting instance
  44. public $apiPayrollInstance; // payroll au instance
  45. public $xeroTenantId;
  46. public function __construct($office)
  47. {
  48. $this->office = $office;
  49. add_action('init', array($this, 'init_wp'));
  50. add_action('after_setup_theme', array($this, 'boot_carbon'));
  51. // add_action('init', array('Carbon_Fields\\Carbon_Fields', 'boot'));
  52. add_action( 'plugins_loaded', array( '\\Carbon_Fields\\Carbon_Fields', 'boot' ) );
  53. add_action('carbon_fields_register_fields', array($this, 'build_settings_page'));
  54. add_action('carbon_fields_container_activated', array($this, 'field_activated'));
  55. add_action('parse_request', array($this, 'xero_callback'));
  56. add_shortcode('xero_org_name', array($this, 'xero_org_name'));
  57. add_shortcode('xero_org_contacts', array($this, 'xero_org_contacts'));
  58. add_shortcode('xero_org_invoices', array($this, 'xero_org_invoices'));
  59. add_shortcode('xero_org_pay_items', array($this, 'xero_org_pay_items'));
  60. add_shortcode('xero_org_employees', array($this, 'xero_org_employees'));
  61. add_shortcode('xero_org_clients', array($this, 'xero_org_clients'));
  62. add_shortcode('xero_org_payroll_calendar', array($this, 'xero_org_payroll_calendar'));
  63. add_action('init', array($this, "xero_init"));
  64. add_action('plugins_loaded', array($this, "load_storage"));
  65. // $this->xero_init();
  66. $this->storage = new StorageClass();
  67. }
  68. public function __call($method, $args) {
  69. if ( method_exists($this->XeroOauth1, $method) ) {
  70. syslog(LOG_INFO,"Calling $method");
  71. $this->XeroOauth1->$method($args);
  72. } else {
  73. error_log("$method is not defined" );
  74. }
  75. }
  76. public function xero_init()
  77. {
  78. $this->provider = $this->create_provider();
  79. }
  80. private function create_provider() {
  81. $provider = new \League\OAuth2\Client\Provider\GenericProvider([
  82. 'clientId' => $this->clientID,
  83. 'clientSecret' => $this->clientSecret,
  84. 'redirectUri' => $this->getRedirectURL(),
  85. 'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize',
  86. 'urlAccessToken' => 'https://identity.xero.com/connect/token',
  87. 'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation'
  88. ]);
  89. return $provider;
  90. }
  91. public function load_storage()
  92. {
  93. //$this->storage->read_value();
  94. }
  95. public function boot_carbon()
  96. {
  97. \Carbon_Fields\Carbon_Fields::boot();
  98. }
  99. function build_settings_page()
  100. {
  101. Container::make('theme_options', __('Xero Integration'))
  102. ->set_page_parent('options-general.php')
  103. ->add_fields(array(
  104. Field::make('text', 'xero_oauth2state', 'Xero Oauth2 State')
  105. ->set_attribute('maxLength', 2048)
  106. ->set_attribute('readOnly', true)
  107. ->set_default_value($this->storage->getOauth2State()),
  108. Field::make('text', 'xero_token', 'Xero Token')
  109. ->set_attribute('maxLength', 2048)
  110. ->set_attribute('readOnly', true)
  111. ->set_default_value($this->storage->getSession()['token']),
  112. Field::make('text', 'xero_refresh_token', 'RefreshToken')
  113. ->set_attribute('readOnly', true)
  114. ->set_default_value($this->storage->getSession()['refresh_token']),
  115. Field::make('text', 'xero_id_token', 'ID Token')
  116. ->set_attribute('readOnly', true)
  117. ->set_default_value($this->storage->getSession()['id_token']),
  118. Field::make('text', 'xero_tenant_id', 'Tenant ID')
  119. ->set_attribute('readOnly', true)
  120. ->set_default_value($this->storage->getSession()['tenant_id']),
  121. Field::make('text', 'xero_expires', 'Expires')
  122. ->set_attribute('readOnly', true)
  123. ->set_default_value($this->storage->getSession()['expires']),
  124. Field::make('text', 'xero_expires_human', 'Expires')
  125. ->set_attribute('readOnly', true)
  126. ->set_default_value($this->storage->getSession()['expires_human']),
  127. Field::make('html', 'crb_information_text')
  128. ->set_html('<h1>Connect/Reconnect</h2><p>if the above field is empty,
  129. or the expire date looks suspicous, please reconnect to XeroOauth1 </p>
  130. <form action="/">
  131. <input type="hidden" name="xero_reauth" value="1" />
  132. <input type="submit" class="button button-primary button-large" value="Xero Connect" />
  133. </form>')
  134. ));
  135. $this->storage->read_value();
  136. }
  137. function field_activated()
  138. {
  139. $this->storage->read_value();
  140. $xeroTenantId = (string)$this->storage->getSession()['tenant_id'];
  141. if ($xeroTenantId == "") {
  142. $this->startAuthorization();
  143. } else {
  144. $this->refresh_token();
  145. }
  146. }
  147. public function startAuthorization()
  148. {
  149. // This returns the authorizeUrl with necessary parameters applied (e.g. state).
  150. $authorizationUrl = $this->provider->getAuthorizationUrl($this->options);
  151. // Save the state generated for you and store it to the session.
  152. // For security, on callback we compare the saved state with the one returned to ensure they match.
  153. $this->storage->setOauth2State($this->provider->getState());
  154. // Redirect the user to the authorization URL.
  155. header('Location: ' . $authorizationUrl);
  156. exit();
  157. }
  158. function xero_callback()
  159. {
  160. if (isset($_GET['xero_reauth'])) {
  161. $this->startAuthorization();
  162. return;
  163. }
  164. if (!isset($_GET['xero_callback'])) {
  165. return;
  166. }
  167. // If we don't have an authorization code then get one
  168. if (!isset($_GET['code'])) {
  169. echo "Something went wrong, no authorization code found";
  170. exit("Something went wrong, no authorization code found");
  171. // Check given state against previously stored one to mitigate CSRF attack
  172. } elseif (empty($_GET['state']) || ($_GET['state'] !== $this->storage->getOauth2State())) {
  173. echo "Invalid State";
  174. $this->storage->setOauth2State("");
  175. exit('Invalid state');
  176. } else {
  177. try {
  178. // Try to get an access token using the authorization code grant.
  179. $accessToken = $this->provider->getAccessToken('authorization_code', [
  180. 'code' => $_GET['code']
  181. ]);
  182. $config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken((string)$accessToken->getToken());
  183. $identityInstance = new \XeroAPI\XeroPHP\Api\IdentityApi(
  184. new \GuzzleHttp\Client(),
  185. $config
  186. );
  187. $result = $identityInstance->getConnections();
  188. // Save my tokens, expiration tenant_id
  189. $this->storage->setToken(
  190. $accessToken->getToken(),
  191. $accessToken->getExpires(),
  192. $result[0]->getTenantId(),
  193. $accessToken->getRefreshToken(),
  194. $accessToken->getValues()["id_token"]
  195. );
  196. // related to $this->build_settings_page
  197. $url = "/wp-admin/options-general.php?page=crb_carbon_fields_container_xero_integration.php";
  198. header('Location: ' . $url);
  199. exit();
  200. } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
  201. echo "Xero Callback failed";
  202. exit();
  203. }
  204. }
  205. }
  206. private function getRedirectURL() {
  207. return get_site_url() . "/?xero_callback";
  208. }
  209. function refresh_token($enforced=false)
  210. {
  211. $this->storage->read_value();
  212. $this->xeroTenantId = (string)$this->storage->getSession()['tenant_id'];
  213. if ($this->storage->getHasExpired() || $enforced) {
  214. $this->provider = $this->create_provider();
  215. try {
  216. $newAccessToken = $this->provider->getAccessToken('refresh_token', [
  217. 'refresh_token' => $this->storage->getRefreshToken()
  218. ]);
  219. } catch (\Exception $e) {
  220. $this->startAuthorization();
  221. return;
  222. }
  223. // Save my token, expiration and refresh token
  224. $this->storage->setToken(
  225. $newAccessToken->getToken(),
  226. $newAccessToken->getExpires(),
  227. $this->xeroTenantId,
  228. $newAccessToken->getRefreshToken(),
  229. $newAccessToken->getValues()["id_token"]);
  230. }
  231. }
  232. private function get_accounting_instance() {
  233. $this->refresh_token();
  234. if ($this->apiAccountingInstance == null) {
  235. $this->config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken(
  236. (string)$this->storage->getSession()['token']);
  237. $this->apiAccountingInstance = new \XeroAPI\XeroPHP\Api\AccountingApi(
  238. new \GuzzleHttp\Client(),
  239. $this->config
  240. );
  241. }
  242. return $this->apiAccountingInstance;
  243. }
  244. private function get_payroll_au_instance() {
  245. $this->refresh_token();
  246. if ($this->apiPayrollInstance == null) {
  247. $this->config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken(
  248. (string)$this->storage->getSession()['token']);
  249. $this->config->setDebug(true);
  250. $this->config->setDebugFile("/home/acaresydneycom/public_html/wp-content/plugins/ts/debug.log");
  251. $this->apiPayrollInstance = new \XeroAPI\XeroPHP\Api\PayrollAuApi(
  252. new \GuzzleHttp\Client(),
  253. $this->config
  254. );
  255. }
  256. return $this->apiPayrollInstance;
  257. }
  258. public function xero_org_name()
  259. {
  260. ini_set('display_errors', 'On');
  261. $apiInstance = $this->get_accounting_instance();
  262. $apiResponse = $apiInstance->getOrganisations($this->xeroTenantId);
  263. return 'Organisation Name: <b> ' . $apiResponse->getOrganisations()[0]->getName() . "</b> ";
  264. }
  265. public function xero_org_contacts()
  266. {
  267. ini_set('display_errors', 'On');
  268. $apiInstance = $this->get_accounting_instance();
  269. $apiResponse = $apiInstance->getContacts($this->xeroTenantId);
  270. $contacts = $apiResponse->getContacts();
  271. $message = "<table> ";
  272. $message .= "<tr> <td> # </td>
  273. <td> unique-id </td>
  274. <td> name </td>
  275. <td> Supplier </td>
  276. <td> Customer </td>
  277. <td> Group </td>
  278. <td> Status </td> </tr> ";
  279. $count = 1;
  280. foreach ($contacts as $c) {
  281. $group = "";
  282. foreach ($c->getContactGroups() as $g) {
  283. $group .= $g->getName() . " - " . $g->getStatus() . "<br>";
  284. }
  285. $message .= "<tr> <td>" . $count++ . "</td> " .
  286. "<td> " . $c->getContactId() . "</td> " .
  287. "<td> " . $c->getName() . "</td> " .
  288. "<td> " . ($c->getIsSupplier() ? "yes" : " - ") . "</td> " .
  289. "<td> " . ($c->getIsCustomer() ? "yes" : " - ") . "</td> " .
  290. "<td> " . $group . "</td> " .
  291. "<td> " . $c->getContactStatus() . "</td> " .
  292. "</tr>";
  293. }
  294. $message .= "</table>";
  295. return $message;
  296. }
  297. public function xero_org_invoices() {
  298. ini_set('display_errors', 'On');
  299. $apiInstance = $this->get_accounting_instance();
  300. $apiResponse = $apiInstance->getInvoices($this->xeroTenantId);
  301. $invoices = $apiResponse->getInvoices();
  302. $message = "<table> ";
  303. $message .= "<tr> <td> # </td>
  304. <td> invoice num</td>
  305. <td> date </td>
  306. <td> contact </td>
  307. <td> amount </td>
  308. <td> Type </td>
  309. <td> Status </td> </tr> ";
  310. $count = 1;
  311. foreach ( $invoices as $c) {
  312. $strDate = "";
  313. $d = $c->getDate();
  314. if ( $d != null) {
  315. $da = $c->getDateAsDate();
  316. $strDate = $da->format("Y-m-d");
  317. } else {
  318. $strDate = $d;
  319. }
  320. $message .= "<tr> <td>" . $count ++ . "</td> " .
  321. "<td> " . $c->getInvoiceNumber() . "</td> " .
  322. "<td> " . $strDate . "</td> " .
  323. "<td> " . $c->getContact()->getName() . "</td> " .
  324. "<td> " . $c->getTotal() . "</td> " .
  325. "<td> " . $c->getType() . "</td> " .
  326. "<td> " . $c->getStatus() . "</td> " .
  327. "</tr>";
  328. }
  329. $message .= "</table>";
  330. return $message;
  331. }
  332. public function xero_org_pay_items(){
  333. ini_set('display_errors', 'On');
  334. $api = $this->get_payroll_au_instance();
  335. $xeroTenantId = $this->xeroTenantId;
  336. //$xeroTenantId = "e23fd416-3b66-43e9-b908-97fbefa24eb8"; // demo company;
  337. //$xeroTenantId = "4e2521ae-83e6-4895-aa90-b20aa0825ce1"; // Acaresydney ;
  338. $ifModifiedSince = null;
  339. $where = null; // "Status==\"ACTIVE\"";
  340. $order = null; // "EmailAddress%20DESC";
  341. $page = 1;
  342. // $result = null;
  343. try {
  344. $result = $api->getPayItems ($xeroTenantId, $ifModifiedSince, $where, $order, $page);
  345. $rates = $result->getPayItems()->getEarningsRates();
  346. $message = "<table> ";
  347. $message .= "<tr> <td> # </td>
  348. <td> Name </td>
  349. <td> EarningsType </td>
  350. <td> RateType </td>
  351. <td> AccountCode </td>
  352. <td> Multiplier </td>
  353. <td> IsExemptFromTax </td>
  354. <td> IsExemptFromSuper </td>
  355. <td> AccrueLeave </td>
  356. <td> IsReportableAsW1 </td>
  357. <td> UpdatedDateUTC </td>
  358. <td> CurrentRecord </td> </tr> ";
  359. $count = 1;
  360. foreach ( $rates as $r) {
  361. $message .= "<tr> <td>" . $r->getEarningsRateId() . "</td> " .
  362. "<td> " . $r->getName() . "</td> " .
  363. "<td> " . $r->getEarningsType() . "</td> " .
  364. "<td> " . $r->getRateType() . "</td> " .
  365. "<td> " . $r->getAccountCode() . "</td> " .
  366. "<td> " . $r->getTypeOfUnits() . "</td> " .
  367. "<td> " . $r->getRatePerUnit() . "</td> " .
  368. "<td> " . $r->getIsExemptFromTax() . "</td> " .
  369. "<td> " . $r->getIsExemptFromSuper() . "</td> " .
  370. "<td> " . $r->getIsReportableAsW1() . "</td> " .
  371. "<td> " . $r->getUpdatedDateUtc() . "</td> " .
  372. "<td> " . $r->getCurrentRecord() . "</td> " .
  373. "</tr>";
  374. }
  375. $message .= "</table>";
  376. return $message;
  377. } catch (\Exception $e) {
  378. echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
  379. return;
  380. }
  381. }
  382. public function xero_org_employees(){
  383. ini_set('display_errors', 'On');
  384. $api = $this->get_payroll_au_instance();
  385. $xeroTenantId = $this->xeroTenantId;
  386. //$xeroTenantId = "e23fd416-3b66-43e9-b908-97fbefa24eb8"; // demo company;
  387. //$xeroTenantId = "4e2521ae-83e6-4895-aa90-b20aa0825ce1"; // Acaresydney ;
  388. $ifModifiedSince = date("M d Y H:i:s", strtotime("-30 days"));
  389. $where = "Status==\"ACTIVE\"";
  390. $order = null; // "EmailAddress%20DESC";
  391. $page = 1;
  392. // $result = null;
  393. try {
  394. $result = $api->getEmployees($xeroTenantId,$ifModifiedSince,$where,$order,$page);
  395. $employees = $result->getEmployees();
  396. $message = "<table> ";
  397. $message .= "<tr> <td> # </td>
  398. <td> First </td>
  399. <td> Last </td>
  400. <td> Status </td>
  401. <td> Email </td>
  402. <td> DOB </td>
  403. <td> Gender </td>
  404. <td> Phone </td>
  405. <td> Mobile </td>
  406. <td> Start </td>
  407. <td> Group </td>
  408. </tr> ";
  409. $count = 1;
  410. foreach ($employees as $r){
  411. $message .= "<tr> <td>" . $count . "</td> " .
  412. "<td> " . $r->getFirstName() . "</td> " .
  413. "<td> " . $r->getLastName() . "</td> " .
  414. "<td> " . $r->getStatus() . "</td> " .
  415. "<td> " . $r->getEmail() . "</td> " .
  416. "<td> " . $r->getDateOfBirthAsDate()->format("M d Y") . "</td> " .
  417. "<td> " . $r->getGender() . "</td> " .
  418. "<td> " . $r->getPhone() . "</td> " .
  419. "<td> " . $r->getMobile() . "</td> " .
  420. "<td> " . $r->getStartDateAsDate()->format("M d Y") . "</td> " .
  421. "<td> " . $r->getEmployeeGroupName() . "</td> " .
  422. "</tr>";
  423. $count ++;
  424. }
  425. $message .= "</table>";
  426. return $message;
  427. } catch (\Exception $e) {
  428. echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
  429. return;
  430. }
  431. }
  432. public function xero_org_clients(){
  433. ini_set('display_errors', 'On');
  434. try {
  435. $contacts = $this->getClients();
  436. $message = "<table> ";
  437. $message .= "<tr> <td> # </td>
  438. <td> Name </td>
  439. <td> Last </td>
  440. <td> Status </td>
  441. <td> Email </td>
  442. <td> AccountNumber </td>
  443. <td> Addresses </td>
  444. </tr> ";
  445. $count = 1;
  446. foreach ($contacts as $r){
  447. $message .= "<tr> <td>" . $count . " - ". $r->getContactID() . "</td> " .
  448. "<td> " . $r->getFirstName() . "</td> " .
  449. "<td> " . $r->getLastName() . "</td> " .
  450. "<td> " . $r->getContactStatus() . "</td> " .
  451. "<td> " . $r->getEmailAddress() . "</td> " .
  452. "<td> " . $r->getAccountNumber() . "</td> " .
  453. "<td> " . $r->getAddresses() . "</td> " .
  454. "</tr>";
  455. $count ++;
  456. }
  457. $message .= "</table>";
  458. return $message;
  459. } catch (\Exception $e) {
  460. echo 'Exception when calling PayrollAuApi->getPayContacts: ', $e->getMessage(), PHP_EOL;
  461. return;
  462. }
  463. }
  464. public function xero_org_payroll_calendar()
  465. {
  466. // update_option('bts_pay_roll_calendar_last_sync', time());
  467. try {
  468. $result = $this->get_payroll_calendar();
  469. $pc = $result->getPayrollCalendars()[0];
  470. $start = $pc->getStartDateAsDate()->format('Y-m-d');
  471. $finish = new \DateTime($start);
  472. $finish = $finish->modify("+13 days")->format('Y-m-d');
  473. $paydate = $pc->getPaymentDateAsDate()->format('Y-m-d');
  474. $calendar["start"] = $start;
  475. $calendar["finish"] = $finish;
  476. $calendar["paydate"] = $paydate;
  477. return print_r ($calendar);
  478. }catch (\Exception $e) {
  479. echo 'Exception when calling PayrollAuApi->getPayrollCalendar: ', $e->getMessage(), PHP_EOL;
  480. }
  481. //update_option('bts_pay_roll_calendar', $calendar);
  482. }
  483. //
  484. //TS implementation
  485. //
  486. /* sync xero to wp options */
  487. public function init_wp(){
  488. try{
  489. error_log("init_wp is empty");
  490. $this->sync_pay_item();
  491. // $this->add_new_client();
  492. // $this->add_new_employee();
  493. // $this->sync_payroll_calendar();
  494. }catch(\Exception $e){
  495. }
  496. }
  497. private function sync_pay_item() {
  498. if ($this->too_close_to_sync_payitem()){
  499. //return;
  500. }
  501. $api = $this->get_payroll_au_instance();
  502. $xeroTenantId = $this->xeroTenantId;
  503. $page = 1;
  504. try {
  505. $result = $api->getPayItems($xeroTenantId, $ifModifiedSince, $where, $order, $page);
  506. foreach ($result->getPayItems()->getEarningsRates() as $e){
  507. // "EarningsRateID": "34e17d08-237a-4ae2-8115-375d1ff8a9ed",
  508. // "Name": "Overtime Hours (exempt from super)",
  509. // "EarningsType": "OVERTIMEEARNINGS",
  510. // "RateType": "MULTIPLE",
  511. // "AccountCode": "477",
  512. // "Multiplier": 1.5,
  513. // "IsExemptFromTax": true,
  514. // "IsExemptFromSuper": true,
  515. // "AccrueLeave": false,
  516. // "IsReportableAsW1": true,
  517. // "UpdatedDateUTC": "2019-03-16T13:18:19+00:00",
  518. // "CurrentRecord": false
  519. if ($e->getCurrentRecord() == "true"){
  520. $payitem_options[]= array(
  521. 'EarningsRateID' => $e->getEarningsRateID(),
  522. 'Name'=> $e->getName(),
  523. 'EarningsType'=> $e->getEarningstype(),
  524. 'RatePerUnit' => $e->getRatePerUnit(),
  525. 'RateType' => $e->getRateType(),
  526. 'AccountCode' => $e->getAccountCode(),
  527. "Multiplier"=> $e->getMultiplier(),
  528. "IsExemptFromTax" => $e->getIsExemptFromTax(),
  529. "IsExemptFromSuper"=> $e->getIsExemptFromSuper(),
  530. "AccrueLeave" => $e->getAccrueLeave(),
  531. "TypeOfUnits" => $e->getTypeOfUnits(),
  532. "CurrentRecord"=> $e->getCurrentRecord(),
  533. );
  534. }
  535. }
  536. update_option('bts_payitem_earnings_rate', $payitem_options);
  537. update_option('bts_payitem_last_sync', time());
  538. } catch (Exception $e) {
  539. echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
  540. }
  541. }
  542. public function sync_users($mininterval, $employeeonly, $clientsonly){
  543. echo "not implemented "; //TODO;
  544. }
  545. public function sync_payroll_calendar() {
  546. }
  547. private function too_close_to_sync_payitem(){
  548. $lastsync = get_option('bts_payitem_last_sync', 0);
  549. $now = time();
  550. $diff = $now - (int) $lastsync;
  551. return $diff < $this->minimum_sync_interval_in_seconds; //default 10 minutes
  552. }
  553. private function sync_payitem(){
  554. }
  555. private function too_close_to_add_employee(){
  556. $lastsync = get_option('bts_add_employee_last_sync', 0);
  557. $now = time();
  558. $diff = $now - (int) $lastsync;
  559. return $diff < 1.5 * $this->minimum_sync_interval_in_seconds; //default 1.1 * 10 minutes
  560. }
  561. private function too_close_to_add_client(){
  562. $lastsync = get_option('bts_add_client_last_sync', 0);
  563. $now = time();
  564. $diff = $now - (int) $lastsync;
  565. return $diff < 2.0 * $this->minimum_sync_interval_in_seconds; //default 1.2 * 10 minutes
  566. }
  567. private function too_close_to_sync_payroll_calendar(){
  568. $lastsync = get_option('bts_pay_roll_calendar_last_sync', 0);
  569. $now = time();
  570. $diff = $now - (int) $lastsync;
  571. return $diff < 3.0 * $this->minimum_sync_interval_in_seconds; //default 1.3 * 10 minutes
  572. }
  573. public function getClients($contact_group_id = null) {
  574. if ( $contact_group_id == null ){
  575. $contact_group_id = $this->clientContactGroupID;
  576. }
  577. $apiAcc = $this->get_accounting_instance();
  578. $result = $apiAcc->getContactGroup($this->xeroTenantId, $contact_group_id);
  579. $cg = $result->getContactGroups();
  580. $allClients = $cg[0]->getContacts();
  581. $ifModifiedSince = new \DateTime();
  582. $recent = new \DateInterval("P30D");
  583. $ifModifiedSince->sub($recent);
  584. $allContacts = $apiAcc->getContacts($this->xeroTenantId, $ifModifiedSince);
  585. $ret = [];
  586. foreach ( $allContacts as $ac ) {
  587. //search from within the group
  588. $found = false;
  589. $id = $ac->getContactID();
  590. foreach ($allClients as $client) {
  591. $clientID = $client->getContactID();
  592. if ( $clientID == $id ) {
  593. $found = true;
  594. break;
  595. }
  596. }
  597. if ( $found ) {
  598. $ret[] = $ac;
  599. }
  600. }
  601. return $ret;
  602. }
  603. public function get_payroll_calendar()
  604. {
  605. $id = "33dc7df5-3060-4d76-b4da-57c20685d77d"; //fortnightly
  606. $api = $this->get_payroll_au_instance();
  607. $pc = $api->getPayrollCalendar($this->xeroTenantId, $id);
  608. return $pc;
  609. }
  610. }