calcinai / xero-php

A php library for the Xero API, with a cleaner OAuth interface and ORM-like abstraction.
MIT License
359 stars 262 forks source link

PayrollUK - get employees #874

Open pjw345 opened 1 year ago

pjw345 commented 1 year ago

I've set the scope of the authorisation and assure my Xero login has access to payroll as admin (without it I was getting permission denied), but now I get 'Not a UK Customer' exception. The API explorer correctly returns all active employees.

Using this method: $query = new \XeroPHP\Remote\Query($session); $query->from('XeroPHP\Models\PayrollUK\Employee'); return $query->execute();

Alternatively using this method: $xero->load(Employee::class)->execute();

Both version return the same exception. Any pointers as to what I am doing wrong?

pjw345 commented 1 year ago

I believe the issue is related to the fact that the payroll_version is set to version 1.0 in the config_defaults in XeroPHP\Application which is currently PayrollAU.

PayrollUK and PayrollNZ are version 2.0. Setting the payroll_version via the setConfig results in errors in XeroPHP/Remote/Response.php on line 276

calcinai commented 1 year ago

What's the error you get with version 2? I believe some APIs must use JSON now, so potentially that's related?

Apologies, I've never actually used the Payroll APIs, or had a version to test with, so am a little in the dark.

pjw345 commented 1 year ago

Setting config to the following indeed pulls the employees in as json format

        $config = [
            'xero' => [
                'payroll_version' => '2.0'
            ]
        ];

We are running on PHP 8.1 and in Response it fails in parseBody when it gets to findElementErrors. I suspect that it processes $this->parseJSON() but the break should take it out of the foreach loop but in PHP8.1 it only takes it out of the switch statement.

I added a quick hack (see below) and data is now correctly returned.

    //Iterate in priority order
    $processed = false;
    foreach ($this->headers[Request::HEADER_CONTENT_TYPE] as $ct) {
        list($content_type) = explode(';', $ct);

        switch ($content_type) {
            case Request::CONTENT_TYPE_XML:
                $this->parseXML();
                $processed = true;
                break;

            case Request::CONTENT_TYPE_JSON:
                $this->parseJSON();
                $processed = true;
                break;

            case Request::CONTENT_TYPE_HTML:
                $this->parseHTML();
                $processed = true;
                break;

            default:
                //Try the next content type
                continue 2;

        }

        if (!$processed) {
            foreach ($this->elements as $index => $element) {
                $this->findElementErrors($element, $index);
            }
        }

In addition I had to add the endDate field to the Employee class and it's respective get/set functions, but now it works until I do an upgrade which means I'd loose my changes.