0

I try to create a php script to send a xml file via an API exact online .

My file is on /tmp/xxx.xml

php code (connexion on exact online api) :

    <?php



require_once 'ExactApi.php';

// Configuration, change these:
$clientId       = '{x}';
$clientSecret   = 'x';
$redirectUri    = "x";
$division       = "x";

try {

    // Initialize ExactAPI
    $exactApi = new ExactApi('fr', $clientId, $clientSecret, $division);

    $exactApi->getOAuthClient()->setRedirectUri($redirectUri);

    if (!isset($_GET['code'])) {

        // Redirect to Auth-endpoint
        $authUrl = $exactApi->getOAuthClient()->getAuthenticationUrl();
        header('Location: ' . $authUrl, TRUE, 302);
        die('Redirect');

    } else {

        // Receive data from Token-endpoint
        $tokenResult = $exactApi->getOAuthClient()->getAccessToken($_GET['code']);
        $exactApi->setRefreshToken($tokenResult['refresh_token']);

        // List accounts
        $response = $exactApi->sendRequest('crm/Accounts', 'get');
        var_dump($response);

        // Create account
        $response = $exactApi->sendRequest('crm/Accounts', 'post', array(
            'Status'            =>  'C',
            'IsSupplier'        =>  True,
            'Name'              =>  'xx',
            'AddressLine1'      =>  'xx',
            'Postcode'          =>  'xx',
            'City'              =>  'xx',
            'Country'           =>  'xx',
            'Email'             =>  'xx',
            'Phone'             =>  'xx',
            'Website'           =>  'xx'

        ));
        var_dump($response);

    }

}catch(ErrorException $e){

    var_dump($e);

}

ExactApi.php

<?php



require_once 'ExactOAuth.php';

class ExactApi
{

    const METHOD_POST = 'post';

    const URL_API = 'https://start.exactonline.%s/api/v1/';

    /** @var string */
    protected $countryCode;

    /** @var string */
    protected $clientId;

    /** @var string */
    protected $clientSecret;

    /** @var string */
    protected $refreshToken;

    /** @var string */
    protected $accessToken;

    /** @var int */
    protected $expiresIn;

    /** @var string */
    protected $division;

    /** @var ExactOAuth */
    protected $oAuthClient;


    /**
     * @param string $countryCode
     * @param string $clientId
     * @param string $clientSecret
     * @param string $division
     * @param string|NULL $refreshToken
     */
    public function __construct($countryCode, $clientId, $clientSecret, $division, $refreshToken = NULL)
    {
        $this->countryCode = $countryCode;
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->refreshToken = $refreshToken;
        $this->division = $division;
    }

    /**
     * @return ExactOAuth
     */
    public function getOAuthClient()
    {
        if (!$this->oAuthClient) {
            $this->oAuthClient = new ExactOAuth(
                $this->countryCode, $this->clientId, $this->clientSecret
            );
        }

        return $this->oAuthClient;
    }

    /**
     * @param string $token
     */
    public function setRefreshToken($token)
    {
        $this->refreshToken = $token;
    }

    /**
     * @return string|FALSE
     * @throws \ErrorException
     */
    protected function initAccessToken()
    {
        if (empty($this->accessToken) || $this->isExpired()) {

            if (empty($this->refreshToken)) {
                throw new \ErrorException('Refresh token is not specified.');
            }

            $refreshed =  $this->getOAuthClient()->refreshAccessToken($this->refreshToken);
            if (!$refreshed) {
                return FALSE;
            }
            $this->setExpiresIn($refreshed['expires_in']);
            $this->refreshToken = $refreshed['refresh_token'];
            $this->accessToken = $refreshed['access_token'];
        }

        return $this->accessToken;
    }

    /**
     * @param int $expiresInTime
     */
    protected function setExpiresIn($expiresInTime)
    {
        $this->expiresIn = time() + $expiresInTime;
    }

    /**
     * @return int
     */
    protected function isExpired()
    {
        return $this->expiresIn > time();
    }

    /**
     * @param string $resourceUrl
     * @param array|NULL $params
     * @return string
     */
    protected function getRequestUrl($resourceUrl, $params = NULL)
    {
        $resourceUrlParts = parse_url($resourceUrl);
        $baseUrl = sprintf(self::URL_API, $this->countryCode);
        $apiUrl = $baseUrl . $this->division.'/'.$resourceUrlParts['path'];

        if (isset($resourceUrlParts['query'])) {
            $apiUrl .= '?' . $resourceUrlParts['query'];
        } else
        if ($params && is_array($params)) {
            $apiUrl .= '?' . http_build_query($params, '', '&');
        }

        return $apiUrl;
    }

    /**
     * @param string $url
     * @param string $method
     * @param array|NULL $payload
     * @return string
     */
    public function sendRequest($url, $method, $payload = NULL)
    {
        if ($payload && !is_array($payload)) {
            throw new \ErrorException('Payload is not valid.');
        }

        if (!$accessToken = $this->initAccessToken()) {
            throw new \ErrorException('Access token was not initialized');
        }

        $requestUrl = $this->getRequestUrl($url, array(
            'access_token' => $accessToken
        ));

        // Base cURL option
        $curlOpt = array();
        $curlOpt[CURLOPT_URL] = $requestUrl;
        $curlOpt[CURLOPT_RETURNTRANSFER] = TRUE;
        $curlOpt[CURLOPT_SSL_VERIFYPEER] = TRUE;
        $curlOpt[CURLOPT_HEADER] = false;

        if ($method == self::METHOD_POST) {

            $curlOpt[CURLOPT_HTTPHEADER] = array(
                'Content-Type:application/json', 
                'access_token:' . $accessToken, 
                'Content-length: ' . strlen(json_encode($payload))
            );
            $curlOpt[CURLOPT_POSTFIELDS] = json_encode($payload);
            $curlOpt[CURLOPT_CUSTOMREQUEST] = strtoupper($method);
        }

        $curlHandle = curl_init();
        curl_setopt_array($curlHandle, $curlOpt);

        return curl_exec($curlHandle);
    }

}

ExactOAuth.php

<?php



class ExactOAuth
{

    const URL_AUTH = 'https://start.exactonline.%s/api/oauth2/auth';
    const URL_TOKEN = 'https://start.exactonline.%s/api/oauth2/token';

    const GRANT_AUTHORIZATION_CODE = 'authorization_code';
    const GRANT_REFRESH_TOKEN = 'refresh_token';

    const RESPONSE_TYPE_CODE = 'code';

    /** @var string */
    public $clientId;

    /** @var string */
    public $clientSecret;

    /** @var string */
    public $countryCode;

    /** @var string */
    public $redirectUri;

    /**
     * @param string $countryCode
     * @param string $clientId
     * @param string $clientSecret
     */
    public function __construct($countryCode, $clientId, $clientSecret)
    {
        $this->clientId = $clientId;
        $this->clientSecret = $clientSecret;
        $this->countryCode = $countryCode;
    }

    /**
     * @param string|NULL $redirectUri
     * @param string $responseType
     * @return string
     * @throws \ErrorException
     */
    public function getAuthenticationUrl($redirectUri = NULL, $responseType = self::RESPONSE_TYPE_CODE)
    {
        if (empty($this->redirectUri) && empty($redirectUri)) {
            throw new \ErrorException('Redirect Uri is not specified.');
        }

        $params = array(
            'client_id' => $this->clientId,
            'redirect_uri' => $redirectUri ? $redirectUri : $this->redirectUri,
            'response_type' => $responseType
        );

        $url = sprintf(self::URL_AUTH, $this->countryCode);

        return $url . '?' . http_build_query($params, '', '&');
    }

    /**
     * @param string $code
     * @param string|NULL $redirectUri
     * @param string $grantType
     * @return array {access_token, token_type, expires_in, refresh_token}
     * @throws \ErrorException
     */
    public function getAccessToken($code, $redirectUri = NULL, $grantType = self::GRANT_AUTHORIZATION_CODE)
    {
        if (empty($this->redirectUri) && empty($redirectUri)) {
            throw new \ErrorException('Redirect Uri is not specified.');
        }

        $params = array(
            'code' => $code,
            'client_id' => $this->clientId,
            'grant_type' => $grantType,
            'client_secret' => $this->clientSecret,
            'redirect_uri' => $redirectUri ? $redirectUri : $this->redirectUri,
        );

        $url = sprintf(self::URL_TOKEN, $this->countryCode);

        return $this->getResponse($url, $params);
    }

    /**
     * @param string $refreshToken
     * @return array {access_token, expires_in, refresh_token}
     */
    public function refreshAccessToken($refreshToken)
    {
        $params = array(
            'refresh_token' => $refreshToken,
            'grant_type' => self::GRANT_REFRESH_TOKEN,
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret
        );

        $url = sprintf(self::URL_TOKEN, $this->countryCode);

        return $this->getResponse($url, $params);
    }

    /**
     * @param string $url
     * @param array $params
     * @return array|NULL
     */
    public function getResponse($url, $params)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params, '', '&'));
        $result = curl_exec($ch);

        $decodedResult = json_decode($result, TRUE);

        if (isset($decodedResult['error'])) {
            return FALSE;
        }

        return $decodedResult;
    }

    /**
     * @param string $uri
     */
    public function setRedirectUri($uri)
    {
        $this->redirectUri = $uri;
    }

}

I would like to send a xml file (xxx.xml)

<?xml version="1.0" encoding="utf-8"?>
<eExact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="eExact-XML.xsd">
<Items><Item code="2M31E93_IM"><IsSalesItem>1</IsSalesItem><Sales><Price><Currency code="EUR" /><Value>80.00</Value><VAT code="VN"></VAT></Price><Unit code="pc"><Description>Piece</Description></Unit></Sales><Costs><Price><Currency code="EUR" /><Value>591.53</Value></Price></Costs><ItemAccounts><ItemAccount><Account code="0000002"></Account><IsPrimary>1</IsPrimary><SupplierItemCode>2M31E93_IM</SupplierItemCode><Purchase><Price><Currency code="EUR" /><Value>50.00</Value><VAT code="AN"></VAT></Price><Unit code="pc"><Description>Piece</Description></Unit></Purchase><CanDropShip>1</CanDropShip></ItemAccount></ItemAccounts></Item></Items>
</eExact>

What should I add in my php file to send my xml file?

Thanks ALL

Guido Leenders
  • 4,232
  • 1
  • 23
  • 43
FAPM
  • 1
  • 6
  • Can you elaborate what you tried to POST the XML to the Exact Online API? Please note that you can test your XML using XML Import from the Exact Online UI. – Guido Leenders Oct 09 '16 at 22:41

1 Answers1

0

Really it's no that hard.

You should use a library that already does this. For instance I use this library (it's very good):

https://github.com/picqer/exact-php-client

I then extended the Connection to add readXML and writeXML properties like so:

https://gist.github.com/alexjeen/6211c363c4efd4c3034cb3f81f7520bf

And then you just call the RawConnection class instead of the normal Connection class of the library:

$connection = new \app\exact\RawConnection();
$connection->setRedirectUrl(Yii::$app->params['exact_redirect_url']);
$connection->setExactClientId(Yii::$app->params['exact_client_id']);
$connection->setExactClientSecret(Yii::$app->params['exact_client_secret']);

And then use it as follows:

$simpleXmlElement = $connection->getXml(1337, 'GLTransactions');

Or POST some XML:

$simpleXmlElement = $connection->postXml(1337, 'GLTransactions', '<xmlstringhere>');
Alex
  • 447
  • 3
  • 8