diff --git a/XeroOauth2.php b/XeroOauth2.php
new file mode 100644
index 0000000..15e2b66
--- /dev/null
+++ b/XeroOauth2.php
@@ -0,0 +1,712 @@
+ ['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'],
+ 'scope1' => [
+ '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'
+ ]
+ ];
+ public $storage;
+ public $config;
+ public $apiAccountingInstance; //accounting instance
+ public $apiPayrollInstance; // payroll au instance
+ public $xeroTenantId;
+
+
+ public function __construct($office)
+ {
+ $this->office = $office;
+ add_action('init', array($this, 'init_wp'));
+ add_action('after_setup_theme', array($this, 'boot_carbon'));
+ // add_action('init', array('Carbon_Fields\\Carbon_Fields', 'boot'));
+ add_action( 'plugins_loaded', array( '\\Carbon_Fields\\Carbon_Fields', 'boot' ) );
+ add_action('carbon_fields_register_fields', array($this, 'build_settings_page'));
+ add_action('carbon_fields_container_activated', array($this, 'field_activated'));
+ add_action('parse_request', array($this, 'xero_callback'));
+
+ add_shortcode('xero_org_name', array($this, 'xero_org_name'));
+ add_shortcode('xero_org_contacts', array($this, 'xero_org_contacts'));
+ add_shortcode('xero_org_invoices', array($this, 'xero_org_invoices'));
+ add_shortcode('xero_org_pay_items', array($this, 'xero_org_pay_items'));
+ add_shortcode('xero_org_employees', array($this, 'xero_org_employees'));
+ add_shortcode('xero_org_clients', array($this, 'xero_org_clients'));
+ add_shortcode('xero_org_payroll_calendar', array($this, 'xero_org_payroll_calendar'));
+
+
+
+ add_action('init', array($this, "xero_init"));
+ add_action('plugins_loaded', array($this, "load_storage"));
+ // $this->xero_init();
+ $this->storage = new StorageClass();
+ }
+
+ public function __call($method, $args) {
+ if ( method_exists($this->XeroOauth1, $method) ) {
+ syslog(LOG_INFO,"Calling $method");
+ $this->XeroOauth1->$method($args);
+ } else {
+ error_log("$method is not defined" );
+ }
+ }
+
+ public function xero_init()
+ {
+ $this->provider = $this->create_provider();
+
+ }
+
+ private function create_provider() {
+ $provider = new \League\OAuth2\Client\Provider\GenericProvider([
+ 'clientId' => $this->clientID,
+ 'clientSecret' => $this->clientSecret,
+ 'redirectUri' => $this->getRedirectURL(),
+ 'urlAuthorize' => 'https://login.xero.com/identity/connect/authorize',
+ 'urlAccessToken' => 'https://identity.xero.com/connect/token',
+ 'urlResourceOwnerDetails' => 'https://api.xero.com/api.xro/2.0/Organisation'
+ ]);
+ return $provider;
+ }
+
+ public function load_storage()
+ {
+ //$this->storage->read_value();
+ }
+
+ public function boot_carbon()
+ {
+ \Carbon_Fields\Carbon_Fields::boot();
+ }
+
+
+ function build_settings_page()
+ {
+ Container::make('theme_options', __('Xero Integration'))
+ ->set_page_parent('options-general.php')
+ ->add_fields(array(
+ Field::make('text', 'xero_oauth2state', 'Xero Oauth2 State')
+ ->set_attribute('maxLength', 2048)
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getOauth2State()),
+ Field::make('text', 'xero_token', 'Xero Token')
+ ->set_attribute('maxLength', 2048)
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['token']),
+ Field::make('text', 'xero_refresh_token', 'RefreshToken')
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['refresh_token']),
+ Field::make('text', 'xero_id_token', 'ID Token')
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['id_token']),
+ Field::make('text', 'xero_tenant_id', 'Tenant ID')
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['tenant_id']),
+ Field::make('text', 'xero_expires', 'Expires')
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['expires']),
+ Field::make('text', 'xero_expires_human', 'Expires')
+ ->set_attribute('readOnly', true)
+ ->set_default_value($this->storage->getSession()['expires_human']),
+
+ Field::make('html', 'crb_information_text')
+ ->set_html('
Connect/Reconnect
if the above field is empty,
+ or the expire date looks suspicous, please reconnect to XeroOauth1
+ ')
+ ));
+
+ $this->storage->read_value();
+ }
+
+
+ function field_activated()
+ {
+ $this->storage->read_value();
+ $xeroTenantId = (string)$this->storage->getSession()['tenant_id'];
+ if ($xeroTenantId == "") {
+ $this->startAuthorization();
+ } else {
+ $this->refresh_token();
+ }
+ }
+
+ public function startAuthorization()
+ {
+ // This returns the authorizeUrl with necessary parameters applied (e.g. state).
+ $authorizationUrl = $this->provider->getAuthorizationUrl($this->options);
+
+ // Save the state generated for you and store it to the session.
+ // For security, on callback we compare the saved state with the one returned to ensure they match.
+ $this->storage->setOauth2State($this->provider->getState());
+
+ // Redirect the user to the authorization URL.
+ header('Location: ' . $authorizationUrl);
+ exit();
+ }
+
+
+ function xero_callback()
+ {
+ if (isset($_GET['xero_reauth'])) {
+ $this->startAuthorization();
+ return;
+ }
+ if (!isset($_GET['xero_callback'])) {
+ return;
+ }
+ // If we don't have an authorization code then get one
+ if (!isset($_GET['code'])) {
+ echo "Something went wrong, no authorization code found";
+ exit("Something went wrong, no authorization code found");
+
+ // Check given state against previously stored one to mitigate CSRF attack
+ } elseif (empty($_GET['state']) || ($_GET['state'] !== $this->storage->getOauth2State())) {
+ echo "Invalid State";
+ $this->storage->setOauth2State("");
+ exit('Invalid state');
+ } else {
+
+ try {
+ // Try to get an access token using the authorization code grant.
+ $accessToken = $this->provider->getAccessToken('authorization_code', [
+ 'code' => $_GET['code']
+ ]);
+
+ $config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken((string)$accessToken->getToken());
+ $identityInstance = new \XeroAPI\XeroPHP\Api\IdentityApi(
+ new \GuzzleHttp\Client(),
+ $config
+ );
+
+ $result = $identityInstance->getConnections();
+
+ // Save my tokens, expiration tenant_id
+ $this->storage->setToken(
+ $accessToken->getToken(),
+ $accessToken->getExpires(),
+ $result[0]->getTenantId(),
+ $accessToken->getRefreshToken(),
+ $accessToken->getValues()["id_token"]
+ );
+
+ // related to $this->build_settings_page
+ $url = "/wp-admin/options-general.php?page=crb_carbon_fields_container_xero_integration.php";
+ header('Location: ' . $url);
+ exit();
+
+ } catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
+ echo "Xero Callback failed";
+ exit();
+ }
+ }
+ }
+
+ private function getRedirectURL() {
+ return get_site_url() . "/?xero_callback";
+ }
+
+ function refresh_token($enforced=false)
+ {
+ $this->storage->read_value();
+ $this->xeroTenantId = (string)$this->storage->getSession()['tenant_id'];
+
+ if ($this->storage->getHasExpired() || $enforced) {
+ $this->provider = $this->create_provider();
+
+ try {
+ $newAccessToken = $this->provider->getAccessToken('refresh_token', [
+ 'refresh_token' => $this->storage->getRefreshToken()
+ ]);
+
+ } catch (\Exception $e) {
+ $this->startAuthorization();
+ return;
+ }
+
+ // Save my token, expiration and refresh token
+ $this->storage->setToken(
+ $newAccessToken->getToken(),
+ $newAccessToken->getExpires(),
+ $this->xeroTenantId,
+ $newAccessToken->getRefreshToken(),
+ $newAccessToken->getValues()["id_token"]);
+ }
+ }
+
+ private function get_accounting_instance() {
+ $this->refresh_token();
+ if ($this->apiAccountingInstance == null) {
+ $this->config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken(
+ (string)$this->storage->getSession()['token']);
+ $this->apiAccountingInstance = new \XeroAPI\XeroPHP\Api\AccountingApi(
+ new \GuzzleHttp\Client(),
+ $this->config
+ );
+ }
+ return $this->apiAccountingInstance;
+ }
+
+ private function get_payroll_au_instance() {
+ $this->refresh_token();
+ if ($this->apiPayrollInstance == null) {
+ $this->config = \XeroAPI\XeroPHP\Configuration::getDefaultConfiguration()->setAccessToken(
+ (string)$this->storage->getSession()['token']);
+ $this->config->setDebug(true);
+ $this->config->setDebugFile("/home/acaresydneycom/public_html/wp-content/plugins/ts/debug.log");
+ $this->apiPayrollInstance = new \XeroAPI\XeroPHP\Api\PayrollAuApi(
+ new \GuzzleHttp\Client(),
+ $this->config
+ );
+ }
+ return $this->apiPayrollInstance;
+ }
+
+ public function xero_org_name()
+ {
+ ini_set('display_errors', 'On');
+ $apiInstance = $this->get_accounting_instance();
+ $apiResponse = $apiInstance->getOrganisations($this->xeroTenantId);
+ return 'Organisation Name: ' . $apiResponse->getOrganisations()[0]->getName() . " ";
+ }
+
+ public function xero_org_contacts()
+ {
+ ini_set('display_errors', 'On');
+ $apiInstance = $this->get_accounting_instance();
+
+ $apiResponse = $apiInstance->getContacts($this->xeroTenantId);
+ $contacts = $apiResponse->getContacts();
+ $message = " ";
+ $message .= " | # |
+ unique-id |
+ name |
+ Supplier |
+ Customer |
+ Group |
+ Status |
";
+ $count = 1;
+ foreach ($contacts as $c) {
+
+ $group = "";
+ foreach ($c->getContactGroups() as $g) {
+ $group .= $g->getName() . " - " . $g->getStatus() . "
";
+ }
+
+ $message .= " | " . $count++ . " | " .
+ " " . $c->getContactId() . " | " .
+ " " . $c->getName() . " | " .
+ " " . ($c->getIsSupplier() ? "yes" : " - ") . " | " .
+ " " . ($c->getIsCustomer() ? "yes" : " - ") . " | " .
+ " " . $group . " | " .
+ " " . $c->getContactStatus() . " | " .
+ "
";
+ }
+ $message .= "
";
+ return $message;
+
+ }
+
+ public function xero_org_invoices() {
+ ini_set('display_errors', 'On');
+ $apiInstance = $this->get_accounting_instance();
+
+ $apiResponse = $apiInstance->getInvoices($this->xeroTenantId);
+ $invoices = $apiResponse->getInvoices();
+
+ $message = " ";
+ $message .= " | # |
+ invoice num |
+ date |
+ contact |
+ amount |
+ Type |
+ Status |
";
+ $count = 1;
+
+ foreach ( $invoices as $c) {
+ $strDate = "";
+ $d = $c->getDate();
+ if ( $d != null) {
+ $da = $c->getDateAsDate();
+ $strDate = $da->format("Y-m-d");
+ } else {
+ $strDate = $d;
+ }
+
+ $message .= " | " . $count ++ . " | " .
+ " " . $c->getInvoiceNumber() . " | " .
+ " " . $strDate . " | " .
+ " " . $c->getContact()->getName() . " | " .
+ " " . $c->getTotal() . " | " .
+ " " . $c->getType() . " | " .
+ " " . $c->getStatus() . " | " .
+ "
";
+ }
+ $message .= "
";
+ return $message;
+
+ }
+
+ public function xero_org_pay_items(){
+ ini_set('display_errors', 'On');
+ $api = $this->get_payroll_au_instance();
+
+ $xeroTenantId = $this->xeroTenantId;
+ //$xeroTenantId = "e23fd416-3b66-43e9-b908-97fbefa24eb8"; // demo company;
+ //$xeroTenantId = "4e2521ae-83e6-4895-aa90-b20aa0825ce1"; // Acaresydney ;
+
+ $ifModifiedSince = null;
+ $where = null; // "Status==\"ACTIVE\"";
+ $order = null; // "EmailAddress%20DESC";
+ $page = 1;
+ // $result = null;
+ try {
+ $result = $api->getPayItems ($xeroTenantId, $ifModifiedSince, $where, $order, $page);
+ $rates = $result->getPayItems()->getEarningsRates();
+ $message = " ";
+ $message .= " | # |
+ Name |
+ EarningsType |
+ RateType |
+ AccountCode |
+ Multiplier |
+ IsExemptFromTax |
+ IsExemptFromSuper |
+ AccrueLeave |
+ IsReportableAsW1 |
+ UpdatedDateUTC |
+ CurrentRecord |
";
+ $count = 1;
+
+ foreach ( $rates as $r) {
+ $message .= " | " . $r->getEarningsRateId() . " | " .
+ " " . $r->getName() . " | " .
+ " " . $r->getEarningsType() . " | " .
+ " " . $r->getRateType() . " | " .
+ " " . $r->getAccountCode() . " | " .
+ " " . $r->getTypeOfUnits() . " | " .
+ " " . $r->getRatePerUnit() . " | " .
+ " " . $r->getIsExemptFromTax() . " | " .
+ " " . $r->getIsExemptFromSuper() . " | " .
+ " " . $r->getIsReportableAsW1() . " | " .
+ " " . $r->getUpdatedDateUtc() . " | " .
+ " " . $r->getCurrentRecord() . " | " .
+ "
";
+ }
+ $message .= "
";
+ return $message;
+ } catch (\Exception $e) {
+ echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
+ return;
+ }
+ }
+
+ public function xero_org_employees(){
+ ini_set('display_errors', 'On');
+ $api = $this->get_payroll_au_instance();
+
+ $xeroTenantId = $this->xeroTenantId;
+ //$xeroTenantId = "e23fd416-3b66-43e9-b908-97fbefa24eb8"; // demo company;
+ //$xeroTenantId = "4e2521ae-83e6-4895-aa90-b20aa0825ce1"; // Acaresydney ;
+
+ $ifModifiedSince = date("M d Y H:i:s", strtotime("-30 days"));
+ $where = "Status==\"ACTIVE\"";
+ $order = null; // "EmailAddress%20DESC";
+ $page = 1;
+ // $result = null;
+ try {
+ $result = $api->getEmployees($xeroTenantId,$ifModifiedSince,$where,$order,$page);
+ $employees = $result->getEmployees();
+ $message = " ";
+ $message .= " | # |
+ First |
+ Last |
+ Status |
+ Email |
+ DOB |
+ Gender |
+ Phone |
+ Mobile |
+ Start |
+ Group |
+
";
+ $count = 1;
+ foreach ($employees as $r){
+
+ $message .= " | " . $count . " | " .
+ " " . $r->getFirstName() . " | " .
+ " " . $r->getLastName() . " | " .
+ " " . $r->getStatus() . " | " .
+ " " . $r->getEmail() . " | " .
+ " " . $r->getDateOfBirthAsDate()->format("M d Y") . " | " .
+ " " . $r->getGender() . " | " .
+ " " . $r->getPhone() . " | " .
+ " " . $r->getMobile() . " | " .
+ " " . $r->getStartDateAsDate()->format("M d Y") . " | " .
+ " " . $r->getEmployeeGroupName() . " | " .
+ "
";
+ $count ++;
+ }
+ $message .= "
";
+ return $message;
+ } catch (\Exception $e) {
+ echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
+ return;
+ }
+ }
+
+ public function xero_org_clients(){
+ ini_set('display_errors', 'On');
+ try {
+ $contacts = $this->getClients();
+ $message = " ";
+ $message .= " | # |
+ Name |
+ Last |
+ Status |
+ Email |
+ AccountNumber |
+ Addresses |
+
";
+ $count = 1;
+ foreach ($contacts as $r){
+
+ $message .= " | " . $count . " - ". $r->getContactID() . " | " .
+ " " . $r->getFirstName() . " | " .
+ " " . $r->getLastName() . " | " .
+ " " . $r->getContactStatus() . " | " .
+ " " . $r->getEmailAddress() . " | " .
+ " " . $r->getAccountNumber() . " | " .
+ " " . $r->getAddresses() . " | " .
+ "
";
+ $count ++;
+ }
+ $message .= "
";
+ return $message;
+ } catch (\Exception $e) {
+ echo 'Exception when calling PayrollAuApi->getPayContacts: ', $e->getMessage(), PHP_EOL;
+ return;
+ }
+ }
+
+
+ public function xero_org_payroll_calendar()
+ {
+ // update_option('bts_pay_roll_calendar_last_sync', time());
+ try {
+ $result = $this->get_payroll_calendar();
+ $pc = $result->getPayrollCalendars()[0];
+ $start = $pc->getStartDateAsDate()->format('Y-m-d');
+ $finish = new \DateTime($start);
+ $finish = $finish->modify("+13 days")->format('Y-m-d');
+ $paydate = $pc->getPaymentDateAsDate()->format('Y-m-d');
+ $calendar["start"] = $start;
+ $calendar["finish"] = $finish;
+ $calendar["paydate"] = $paydate;
+
+ return print_r ($calendar);
+ }catch (\Exception $e) {
+ echo 'Exception when calling PayrollAuApi->getPayrollCalendar: ', $e->getMessage(), PHP_EOL;
+ }
+ //update_option('bts_pay_roll_calendar', $calendar);
+ }
+
+ //
+ //TS implementation
+ //
+
+ /* sync xero to wp options */
+ public function init_wp(){
+ try{
+ error_log("init_wp is empty");
+ $this->sync_pay_item();
+// $this->add_new_client();
+// $this->add_new_employee();
+// $this->sync_payroll_calendar();
+ }catch(\Exception $e){
+
+ }
+ }
+
+ private function sync_pay_item() {
+ if ($this->too_close_to_sync_payitem()){
+ //return;
+ }
+
+ $api = $this->get_payroll_au_instance();
+ $xeroTenantId = $this->xeroTenantId;
+ $page = 1;
+ try {
+ $result = $api->getPayItems($xeroTenantId, $ifModifiedSince, $where, $order, $page);
+
+
+
+ foreach ($result->getPayItems()->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(),
+ "TypeOfUnits" => $e->getTypeOfUnits(),
+ "CurrentRecord"=> $e->getCurrentRecord(),
+ );
+ }
+ }
+ update_option('bts_payitem_earnings_rate', $payitem_options);
+ update_option('bts_payitem_last_sync', time());
+
+
+ } catch (Exception $e) {
+ echo 'Exception when calling PayrollAuApi->getPayItems: ', $e->getMessage(), PHP_EOL;
+ }
+ }
+
+ public function sync_users($mininterval, $employeeonly, $clientsonly){
+ echo "not implemented "; //TODO;
+ }
+
+ public function sync_payroll_calendar() {
+
+ }
+
+ 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
+ }
+
+ private function sync_payitem(){
+
+
+ }
+
+
+ private function too_close_to_add_employee(){
+ $lastsync = get_option('bts_add_employee_last_sync', 0);
+ $now = time();
+ $diff = $now - (int) $lastsync;
+ return $diff < 1.5 * $this->minimum_sync_interval_in_seconds; //default 1.1 * 10 minutes
+ }
+ private function too_close_to_add_client(){
+ $lastsync = get_option('bts_add_client_last_sync', 0);
+ $now = time();
+ $diff = $now - (int) $lastsync;
+ return $diff < 2.0 * $this->minimum_sync_interval_in_seconds; //default 1.2 * 10 minutes
+ }
+ private function too_close_to_sync_payroll_calendar(){
+ $lastsync = get_option('bts_pay_roll_calendar_last_sync', 0);
+ $now = time();
+ $diff = $now - (int) $lastsync;
+ return $diff < 3.0 * $this->minimum_sync_interval_in_seconds; //default 1.3 * 10 minutes
+ }
+
+
+
+
+
+
+ public function getClients($contact_group_id = null) {
+ if ( $contact_group_id == null ){
+ $contact_group_id = $this->clientContactGroupID;
+ }
+ $apiAcc = $this->get_accounting_instance();
+ $result = $apiAcc->getContactGroup($this->xeroTenantId, $contact_group_id);
+ $cg = $result->getContactGroups();
+ $allClients = $cg[0]->getContacts();
+
+ $ifModifiedSince = new \DateTime();
+ $recent = new \DateInterval("P30D");
+ $ifModifiedSince->sub($recent);
+
+
+ $allContacts = $apiAcc->getContacts($this->xeroTenantId, $ifModifiedSince);
+ $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 get_payroll_calendar()
+ {
+ $id = "33dc7df5-3060-4d76-b4da-57c20685d77d"; //fortnightly
+ $api = $this->get_payroll_au_instance();
+
+ $pc = $api->getPayrollCalendar($this->xeroTenantId, $id);
+ return $pc;
+ }
+
+}
\ No newline at end of file
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..0f9d205
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,7 @@
+{
+ "require": {
+ "xeroapi/xero-php-oauth2": "2.8.1",
+ "htmlburger/carbon-fields": "^3.3",
+ "guzzlehttp/psr7": "1.8.2"
+ }
+}
diff --git a/composer.lock b/composer.lock
new file mode 100644
index 0000000..976c9fa
--- /dev/null
+++ b/composer.lock
@@ -0,0 +1,778 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
+ "This file is @generated automatically"
+ ],
+ "content-hash": "fd8f5e90c9c2ce1e1f6b11421a29aa4a",
+ "packages": [
+ {
+ "name": "firebase/php-jwt",
+ "version": "v5.4.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/firebase/php-jwt.git",
+ "reference": "d2113d9b2e0e349796e72d2a63cf9319100382d2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d2113d9b2e0e349796e72d2a63cf9319100382d2",
+ "reference": "d2113d9b2e0e349796e72d2a63cf9319100382d2",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": ">=4.8 <=9"
+ },
+ "suggest": {
+ "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Firebase\\JWT\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "BSD-3-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Neuman Vong",
+ "email": "neuman+pear@twilio.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Anant Narayanan",
+ "email": "anant@php.net",
+ "role": "Developer"
+ }
+ ],
+ "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.",
+ "homepage": "https://github.com/firebase/php-jwt",
+ "keywords": [
+ "jwt",
+ "php"
+ ],
+ "support": {
+ "issues": "https://github.com/firebase/php-jwt/issues",
+ "source": "https://github.com/firebase/php-jwt/tree/v5.4.0"
+ },
+ "time": "2021-06-23T19:00:23+00:00"
+ },
+ {
+ "name": "guzzlehttp/guzzle",
+ "version": "7.3.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/guzzle.git",
+ "reference": "7008573787b430c1c1f650e3722d9bba59967628"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7008573787b430c1c1f650e3722d9bba59967628",
+ "reference": "7008573787b430c1c1f650e3722d9bba59967628",
+ "shasum": ""
+ },
+ "require": {
+ "ext-json": "*",
+ "guzzlehttp/promises": "^1.4",
+ "guzzlehttp/psr7": "^1.7 || ^2.0",
+ "php": "^7.2.5 || ^8.0",
+ "psr/http-client": "^1.0"
+ },
+ "provide": {
+ "psr/http-client-implementation": "1.0"
+ },
+ "require-dev": {
+ "bamarni/composer-bin-plugin": "^1.4.1",
+ "ext-curl": "*",
+ "php-http/client-integration-tests": "^3.0",
+ "phpunit/phpunit": "^8.5.5 || ^9.3.5",
+ "psr/log": "^1.1"
+ },
+ "suggest": {
+ "ext-curl": "Required for CURL handler support",
+ "ext-intl": "Required for Internationalized Domain Name (IDN) support",
+ "psr/log": "Required for using the Log middleware"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "7.3-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com",
+ "homepage": "https://sagikazarmark.hu"
+ }
+ ],
+ "description": "Guzzle is a PHP HTTP client library",
+ "homepage": "http://guzzlephp.org/",
+ "keywords": [
+ "client",
+ "curl",
+ "framework",
+ "http",
+ "http client",
+ "psr-18",
+ "psr-7",
+ "rest",
+ "web service"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/guzzle/issues",
+ "source": "https://github.com/guzzle/guzzle/tree/7.3.0"
+ },
+ "funding": [
+ {
+ "url": "https://github.com/GrahamCampbell",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/Nyholm",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/alexeyshockov",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/gmponos",
+ "type": "github"
+ }
+ ],
+ "time": "2021-03-23T11:33:13+00:00"
+ },
+ {
+ "name": "guzzlehttp/promises",
+ "version": "1.4.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/promises.git",
+ "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/8e7d04f1f6450fef59366c399cfad4b9383aa30d",
+ "reference": "8e7d04f1f6450fef59366c399cfad4b9383aa30d",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "symfony/phpunit-bridge": "^4.4 || ^5.1"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.4-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Promise\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Guzzle promises library",
+ "keywords": [
+ "promise"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/promises/issues",
+ "source": "https://github.com/guzzle/promises/tree/1.4.1"
+ },
+ "time": "2021-03-07T09:25:29+00:00"
+ },
+ {
+ "name": "guzzlehttp/psr7",
+ "version": "1.8.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/guzzle/psr7.git",
+ "reference": "dc960a912984efb74d0a90222870c72c87f10c91"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/guzzle/psr7/zipball/dc960a912984efb74d0a90222870c72c87f10c91",
+ "reference": "dc960a912984efb74d0a90222870c72c87f10c91",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.4.0",
+ "psr/http-message": "~1.0",
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
+ },
+ "provide": {
+ "psr/http-message-implementation": "1.0"
+ },
+ "require-dev": {
+ "ext-zlib": "*",
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.14 || ^7.5.20 || ^8.5.8 || ^9.3.10"
+ },
+ "suggest": {
+ "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.7-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "GuzzleHttp\\Psr7\\": "src/"
+ },
+ "files": [
+ "src/functions_include.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ },
+ {
+ "name": "Tobias Schultze",
+ "homepage": "https://github.com/Tobion"
+ }
+ ],
+ "description": "PSR-7 message implementation that also provides common utility methods",
+ "keywords": [
+ "http",
+ "message",
+ "psr-7",
+ "request",
+ "response",
+ "stream",
+ "uri",
+ "url"
+ ],
+ "support": {
+ "issues": "https://github.com/guzzle/psr7/issues",
+ "source": "https://github.com/guzzle/psr7/tree/1.8.2"
+ },
+ "time": "2021-04-26T09:17:50+00:00"
+ },
+ {
+ "name": "htmlburger/carbon-fields",
+ "version": "v3.3.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/htmlburger/carbon-fields.git",
+ "reference": "dd5663e14c6db365323b688dbae1cfbeaf14bee7"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/htmlburger/carbon-fields/zipball/dd5663e14c6db365323b688dbae1cfbeaf14bee7",
+ "reference": "dd5663e14c6db365323b688dbae1cfbeaf14bee7",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3"
+ },
+ "require-dev": {
+ "mockery/mockery": "^0.9.7",
+ "phpunit/phpunit": "~4.8"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Carbon_Fields\\": "core/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0-only"
+ ],
+ "authors": [
+ {
+ "name": "htmlBurger",
+ "email": "wordpress@htmlburger.com",
+ "homepage": "https://htmlburger.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Miroslav Mitev",
+ "email": "mmitev.2create@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Atanas Angelov",
+ "email": "atanas.angelov.dev@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Georgi Stoyanov",
+ "email": "stoyanov.gs@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Plamen Kostadinov",
+ "email": "pkostadinov.2create@gmail.com",
+ "homepage": "http://plasmen.info/",
+ "role": "Developer"
+ },
+ {
+ "name": "Stanimir Panchev",
+ "email": "Stan4omir@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Marin Atanasov",
+ "email": "contact@marinatanasov.com",
+ "homepage": "http://marinatanasov.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Siyan Panayotov",
+ "homepage": "http://siyanpanayotov.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Peter Petrov",
+ "email": "peter.petrov89@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Stanimir Stoyanov",
+ "email": "stanimir.k.stoyanov@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Kaloyan Ivanov",
+ "email": "kaloyanxivanov@gmail.com",
+ "homepage": "http://vilepixels.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Georgi Popov",
+ "homepage": "http://magadanski.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "German Velchev",
+ "email": "germozy@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Rashko Petrov",
+ "email": "brutalenemy666@gmail.com",
+ "homepage": "http://errorfactory.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Alexander Panayotov",
+ "email": "alexander.panayotov@gmail.com",
+ "homepage": "http://alexanderpanayotov.com/",
+ "role": "Developer"
+ },
+ {
+ "name": "Viktor Vasilev",
+ "email": "liberalcho@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Georgi Georgiev",
+ "email": "george.georgiev96@gmail.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Atanas Vasilev",
+ "email": "atanasvasilev91@gmail.com",
+ "role": "Developer"
+ }
+ ],
+ "description": "WordPress developer-friendly custom fields for post types, taxonomy terms, users, comments, widgets, options and more.",
+ "homepage": "http://carbonfields.net/",
+ "support": {
+ "docs": "http://carbonfields.net/docs/",
+ "email": "wordpress@htmlburger.com",
+ "issues": "https://github.com/htmlburger/carbon-fields/issues",
+ "source": "https://github.com/htmlburger/carbon-fields"
+ },
+ "time": "2021-04-22T13:24:34+00:00"
+ },
+ {
+ "name": "league/oauth2-client",
+ "version": "2.6.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/thephpleague/oauth2-client.git",
+ "reference": "badb01e62383430706433191b82506b6df24ad98"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/badb01e62383430706433191b82506b6df24ad98",
+ "reference": "badb01e62383430706433191b82506b6df24ad98",
+ "shasum": ""
+ },
+ "require": {
+ "guzzlehttp/guzzle": "^6.0 || ^7.0",
+ "paragonie/random_compat": "^1 || ^2 || ^9.99",
+ "php": "^5.6 || ^7.0 || ^8.0"
+ },
+ "require-dev": {
+ "mockery/mockery": "^1.3",
+ "php-parallel-lint/php-parallel-lint": "^1.2",
+ "phpunit/phpunit": "^5.7 || ^6.0 || ^9.3",
+ "squizlabs/php_codesniffer": "^2.3 || ^3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-2.x": "2.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "League\\OAuth2\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Alex Bilbie",
+ "email": "hello@alexbilbie.com",
+ "homepage": "http://www.alexbilbie.com",
+ "role": "Developer"
+ },
+ {
+ "name": "Woody Gilk",
+ "homepage": "https://github.com/shadowhand",
+ "role": "Contributor"
+ }
+ ],
+ "description": "OAuth 2.0 Client Library",
+ "keywords": [
+ "Authentication",
+ "SSO",
+ "authorization",
+ "identity",
+ "idp",
+ "oauth",
+ "oauth2",
+ "single sign on"
+ ],
+ "support": {
+ "issues": "https://github.com/thephpleague/oauth2-client/issues",
+ "source": "https://github.com/thephpleague/oauth2-client/tree/2.6.0"
+ },
+ "time": "2020-10-28T02:03:40+00:00"
+ },
+ {
+ "name": "paragonie/random_compat",
+ "version": "v9.99.100",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/paragonie/random_compat.git",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">= 7"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "4.*|5.*",
+ "vimeo/psalm": "^1"
+ },
+ "suggest": {
+ "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
+ },
+ "type": "library",
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Paragon Initiative Enterprises",
+ "email": "security@paragonie.com",
+ "homepage": "https://paragonie.com"
+ }
+ ],
+ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
+ "keywords": [
+ "csprng",
+ "polyfill",
+ "pseudorandom",
+ "random"
+ ],
+ "support": {
+ "email": "info@paragonie.com",
+ "issues": "https://github.com/paragonie/random_compat/issues",
+ "source": "https://github.com/paragonie/random_compat"
+ },
+ "time": "2020-10-15T08:29:30+00:00"
+ },
+ {
+ "name": "psr/http-client",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-client.git",
+ "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+ "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.0 || ^8.0",
+ "psr/http-message": "^1.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Client\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP clients",
+ "homepage": "https://github.com/php-fig/http-client",
+ "keywords": [
+ "http",
+ "http-client",
+ "psr",
+ "psr-18"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-client/tree/master"
+ },
+ "time": "2020-06-29T06:28:15+00:00"
+ },
+ {
+ "name": "psr/http-message",
+ "version": "1.0.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/php-fig/http-message.git",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.3.0"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-4": {
+ "Psr\\Http\\Message\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "PHP-FIG",
+ "homepage": "http://www.php-fig.org/"
+ }
+ ],
+ "description": "Common interface for HTTP messages",
+ "homepage": "https://github.com/php-fig/http-message",
+ "keywords": [
+ "http",
+ "http-message",
+ "psr",
+ "psr-7",
+ "request",
+ "response"
+ ],
+ "support": {
+ "source": "https://github.com/php-fig/http-message/tree/master"
+ },
+ "time": "2016-08-06T14:39:51+00:00"
+ },
+ {
+ "name": "ralouphie/getallheaders",
+ "version": "3.0.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/ralouphie/getallheaders.git",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
+ },
+ "type": "library",
+ "autoload": {
+ "files": [
+ "src/getallheaders.php"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
+ }
+ ],
+ "description": "A polyfill for getallheaders.",
+ "support": {
+ "issues": "https://github.com/ralouphie/getallheaders/issues",
+ "source": "https://github.com/ralouphie/getallheaders/tree/develop"
+ },
+ "time": "2019-03-08T08:55:37+00:00"
+ },
+ {
+ "name": "xeroapi/xero-php-oauth2",
+ "version": "2.8.1",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/XeroAPI/xero-php-oauth2.git",
+ "reference": "cdf5dbeddff46d25212be596ff474c8bcf7351da"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/XeroAPI/xero-php-oauth2/zipball/cdf5dbeddff46d25212be596ff474c8bcf7351da",
+ "reference": "cdf5dbeddff46d25212be596ff474c8bcf7351da",
+ "shasum": ""
+ },
+ "require": {
+ "ext-curl": "*",
+ "ext-json": "*",
+ "ext-mbstring": "*",
+ "firebase/php-jwt": "^5.0",
+ "guzzlehttp/guzzle": "^6.2 | ^7.0",
+ "guzzlehttp/psr7": "^1.8",
+ "league/oauth2-client": "^2.5.0",
+ "php": ">=5.6"
+ },
+ "require-dev": {
+ "friendsofphp/php-cs-fixer": "~2.12",
+ "phpunit/phpunit": "^4.8",
+ "squizlabs/php_codesniffer": "~2.6"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "XeroAPI\\XeroPHP\\": "lib/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Xero API Team",
+ "homepage": "https://developer.xero.com"
+ }
+ ],
+ "description": "Xero official PHP SDK for oAuth2 generated with OpenAPI spec 3",
+ "homepage": "https://github.com/xeroapi/xero-php-oauth2",
+ "keywords": [
+ "api",
+ "openapispec",
+ "php",
+ "rest",
+ "sdk",
+ "xero"
+ ],
+ "support": {
+ "issues": "https://github.com/XeroAPI/xero-php-oauth2/issues",
+ "source": "https://github.com/XeroAPI/xero-php-oauth2/tree/2.8.1"
+ },
+ "time": "2021-08-09T22:52:00+00:00"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": [],
+ "plugin-api-version": "2.1.0"
+}