url = (config('app.env') == 'local' && ! $tryprod) ? 'https://sandbox-quickbooks.api.intuit.com' : 'https://quickbooks.api.intuit.com'; $this->token = $token; Log::debug(sprintf('%s:Intuit API for id [%s]',static::LOGKEY,$token->realm_id)); } /* STATIC */ public static function url(bool $tryprod=FALSE): string { return (config('app.env') == 'local' && ! $tryprod) ? 'https://app.sandbox.qbo.intuit.com/app' : 'https://app.qbo.intuit.com/app'; } /** * Convert an Array to Curl Headers * * @param array $header * @return array Curl Headers */ private function convertHeaders(array $header): array { return collect($header) ->map(function($value,$key) { return sprintf('%s:%s',$key,$value); }) ->values() ->toArray(); } /** * Call the API * * @param string $path * @param array $parameters * @return object|array * @throws \Exception */ private function execute(string $path,array $parameters=[]) { $url = sprintf('%s/%s/company/%s/%s',$this->url,self::VERSION,$this->token->realm_id,$path); $method = Arr::get($parameters,'method','GET'); if ($parameters) Arr::forget($parameters,'method'); // If we are passed an array, we'll do a normal post. switch ($method) { case 'GET': $request = $this->prepareRequest( $url, $parameters, [ 'Accept' => 'application/json', 'Authorization' => sprintf('Bearer %s',$this->token->access_token), 'Content-Type' => 'application/json', ] ); break; case 'POST': $request = $this->prepareRequestPost( $url, $parameters, [ 'Accept' => 'application/json', 'Authorization' => sprintf('Bearer %s',$this->token->access_token), 'Content-Type' => 'application/json', ] ); break; /* case 'PUT': $request = $this->prepareRequestPut( $url, $parameters, [ 'accept: application/json', 'Api-Request-Id: '.$request_id, 'Api-Signature: '.$signature, ] ); break; */ default: throw new \Exception(sprintf('Unknown method: %s',$method)); } $key = md5($path.serialize($parameters)); //Cache::forget($key); $result = Cache::remember($key,self::CACHE_TIME,function() use ($request,$url) { try { $response = curl_exec($request); switch($x=curl_getinfo($request,CURLINFO_HTTP_CODE)) { case 400: case 401: case 403: case 404: dump([$xx=curl_getinfo($request),'response'=>$response]); throw new \Exception(sprintf('CURL exec returned %d: %s (%s)',$x,curl_error($request),serialize($xx))); } curl_close($request); return json_decode(self::CURLOPT_HEADER ? substr($response,curl_getinfo($request,CURLINFO_HEADER_SIZE)) : $response); } catch (\Exception $e) { dump(['error'=>$e->getMessage()]); Log::error(sprintf('%s:Got an error while posting to [%s] (%s)',static::LOGKEY,$url,$e->getMessage()),['m'=>__METHOD__]); curl_close($request); throw new \Exception($e->getMessage()); } }); return $result; } /** * Get a specific customer record * * @param int $id * @param array $parameters * @return Customer * @throws \Exception */ public function getCustomer(int $id,array $parameters=[]): Customer { Log::debug(sprintf('%s:Get a specific customer [%d]',static::LOGKEY,$id)); return new Customer($this->execute('customer/'.$id,$parameters)); } /** * Get a list of our classes * * @param array $parameters * @return ListList * @throws \Exception */ public function getClasses(array $parameters=[]): ListList { Log::debug(sprintf('%s:Get a list of classes',static::LOGKEY)); $key = 'classes'; $parameters['query'] = 'select * from Class'; return new ListList($this->execute('query',$parameters),$key); } /** * Get a list of our clients * * @param array $parameters * @return ListList * @throws \Exception */ public function getCustomers(array $parameters=[]): ListList { Log::debug(sprintf('%s:Get a list of customers',static::LOGKEY)); $key = 'customers'; $parameters['query'] = 'select * from Customer'; return new ListList($this->execute('query',$parameters),$key); } /** * Get a list of our invoices * * @param array $parameters * @return ListList * @throws \Exception */ public function getInvoices(array $parameters=[]): ListList { Log::debug(sprintf('%s:Get a list of invoices',static::LOGKEY)); $key = 'invoices'; $parameters['query'] = 'select * from Invoice'; return new ListList($this->execute('query',$parameters),$key); } /** * Get a list of our items * * @param array $parameters * @return ListList * @throws \Exception */ public function getItems(array $parameters=[]): ListList { Log::debug(sprintf('%s:Get a list of items',static::LOGKEY)); $key = 'items'; $parameters['query'] = 'select * from Item'; return new ListList($this->execute('query',$parameters),$key); } /** * Setup the API call * * @param string $url * @param array $parameters * @param array $headers * @return \CurlHandle */ private function prepareRequest(string $url,array $parameters=[],array $headers=[]): \CurlHandle { $request = curl_init(); curl_setopt($request,CURLOPT_HEADER,self::CURLOPT_HEADER); // debugging set this to TRUE, but it affects our body. curl_setopt($request,CURLOPT_URL,$url.'?'.http_build_query(array_merge($parameters,['minorversion'=>self::MINOR_VERSION]))); curl_setopt($request,CURLOPT_RETURNTRANSFER,TRUE); curl_setopt($request,CURLOPT_CUSTOMREQUEST,'GET'); curl_setopt($request,CURLINFO_HEADER_OUT,TRUE); curl_setopt($request,CURLOPT_SSL_VERIFYPEER,TRUE); curl_setopt($request,CURLOPT_CONNECTTIMEOUT,15); curl_setopt($request,CURLOPT_TIMEOUT,15); if ($headers) curl_setopt($request,CURLOPT_HTTPHEADER,$this->convertHeaders($headers)); return $request; } private function prepareRequestPost(string $url,array $parameters=[],array $headers=[]): \CurlHandle { $request = $this->prepareRequest($url,$parameters,$headers); curl_setopt($request,CURLOPT_CUSTOMREQUEST,'POST'); curl_setopt($request,CURLOPT_POSTFIELDS,json_encode($parameters)); return $request; } /** * Update a customer * * @param array $parameters * @return Customer * @throws \Exception */ public function updateCustomer(array $parameters=[]): Customer { Log::debug(sprintf('%s:Update customer',static::LOGKEY),['params'=>$parameters]); return new Customer($this->execute('customer',array_merge($parameters,['method'=>'POST']))); } }