whoami7 - Manager
:
/
home
/
kckglobal
/
www
/
portal
/
vendor
/
quickbooks
/
v3-php-sdk
/
src
/
DataService
/
Upload File:
files >> //home/kckglobal/www/portal/vendor/quickbooks/v3-php-sdk/src/DataService/DataService.php
<?php /******************************************************************************* * Copyright (c) 2017 Intuit * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ namespace QuickBooksOnline\API\DataService; use QuickBooksOnline\API\Core\CoreHelper; use QuickBooksOnline\API\Core\Http\Serialization\IEntitySerializer; use QuickBooksOnline\API\Core\Http\Serialization\XmlObjectSerializer; use QuickBooksOnline\API\Core\HttpClients\FaultHandler; use QuickBooksOnline\API\Core\HttpClients\RestHandler; use QuickBooksOnline\API\Core\ServiceContext; use QuickBooksOnline\API\Core\CoreConstants; use QuickBooksOnline\API\Core\HttpClients\SyncRestHandler; use QuickBooksOnline\API\Core\HttpClients\RequestParameters; use QuickBooksOnline\API\Core\Http\Serialization\JsonObjectSerializer; use QuickBooksOnline\API\Core\Http\Serialization\SerializationFormat; use QuickBooksOnline\API\Data\IPPAttachable; use QuickBooksOnline\API\Data\IPPEntitlementsResponse; use QuickBooksOnline\API\Data\IPPIntuitEntity; use QuickBooksOnline\API\Data\IPPRecurringTransaction; use QuickBooksOnline\API\Data\IPPTaxService; use QuickBooksOnline\API\Data\IPPid; use QuickBooksOnline\API\Exception\IdsException; use QuickBooksOnline\API\Exception\ServiceException; use QuickBooksOnline\API\Exception\IdsExceptionManager; use QuickBooksOnline\API\Exception\SdkException; use QuickBooksOnline\API\Diagnostics\TraceLevel; use QuickBooksOnline\API\Diagnostics\ContentWriter; use QuickBooksOnline\API\XSD2PHP\src\com\mikebevz\xsd2php\Php2Xml; use QuickBooksOnline\API\Core\OAuth\OAuth2\OAuth2LoginHelper; use QuickBooksOnline\API\Core\OAuth\OAuth2\OAuth2AccessToken; use QuickBooksOnline\API\Core\HttpClients\ClientFactory; use QuickBooksOnline\API\Data\IPPCompanyInfo; use QuickBooksOnline\API\Data\IPPPreferences; /** * Class DataServicd * * This file contains DataService performs CRUD operations on IPP REST APIs. */ class DataService { /** * The METHOD UPDATE. * @var String */ const UPDATE = 'update'; /** * The METHOD FINDBYID. * @var String */ const FINDBYID = 'FindById'; /** * The METHOD ADD. * @var String */ const ADD = 'Add'; /** * The METHOD Delete. * @var String */ const DELETE = 'Delete'; /** * The METHOD VOID. * @var String */ const VOID = 'Void'; /** * The METHOD UPLOAD. * @var String */ const UPLOAD = 'upload'; /** * The METHOD SENDEMAIL. * @var String */ const SENDEMAIL = 'SendEmail'; /** * The Service context object. * @var ServiceContext The service Context of the request */ private $serviceContext; /** * Rest Request Handler for actually sending the request * @var SyncRestHandler */ private $restHandler; /** * Serializer needs to be used fore responce object * @var IEntitySerializer */ private $responseSerializer; /** * Serializer needs to be used for request object * @var IEntitySerializer */ private $requestSerializer; /** * If true, indicates a desire to echo verbose output * @var bool */ private $verbose; /** * If not false, the request from last dataService did not return 2xx * @var FaultHandler */ private $lastError = false; /** * The OAuth 2 Login helper for get RefreshToken * @var OAuth2LoginHelper */ private $OAuth2LoginHelper; /** * A boolean value to decide if excetion will be thrown on non-200 request * @var Boolean */ private $throwExceptionOnError = false; /** * The client to be used for HTTP request. You can choose either defaukt(cURL) or GuzzleHttpClient if that is available * @var String */ private $clientName = CoreConstants::CLIENT_CURL; /** * Initializes a new instance of the DataService class. The old way to construct the dataService. Used by PHP SDK < 3.0.0 * * @param ServiceContext $serviceContext IPP Service Context * @throws SdkException */ public function __construct($serviceContext) { if (null == $serviceContext || !is_object($serviceContext)) { throw new SdkException('Undefined ServiceContext. DataService constructor has NULL or Non_Object ServiceContext as Constructor'); } $this->updateServiceContextSettingsForOthers($serviceContext); } /** * Set the corresponding settings for the dataService based on ServiceContext * @var ServiceContext $serviceContext The service Context for this DataService */ public function updateServiceContextSettingsForOthers($serviceContext) { $this->setupServiceContext($serviceContext); $this->setupSerializers(); $this->useMinorVersion(); $this->setupRestHandler($serviceContext); } /** * Set or Update the ServiceContext of this DataService. * * @var ServiceContext $serviceContext The new ServiceContext passed by. * @return $this */ private function setupServiceContext($serviceContext) { $this->serviceContext = $serviceContext; return $this; } /** * Return the ServiceContext of this DataService * * @return ServiceContext * @throws \Exception ServiceContext is NULL. */ public function getServiceContext() { if (isset($this->serviceContext)) { return $this->serviceContext; } else { throw new SdkException("Trying to Return an Empty Service Context."); } } /** * Set the SyncRest Handler for the DataService. If the client Name changed, the underlying Client that SyncRestHandler used will also changed. * * @var ServiceContext $serviceContext The service Context for this DataService * @return $this * */ protected function setupRestHandler($serviceContext) { if(isset($serviceContext)){ $client = ClientFactory::createClient($this->getClientName()); $this->restHandler = new SyncRestHandler($serviceContext, $client); }else{ throw new SdkException("Can not set the Rest Client based on null ServiceContext."); } return $this; } /** * Return the current Client Name used by DataService * @return String clientName */ public function getClientName(){ return $this->clientName; } /** * PHP SDK currently only support XML for Object Serialization and Deserialization, except for Report Service * * @return $this */ public function useXml() { $serviceContext = $this->getServiceContext(); $serviceContext->useXml(); $this->updateServiceContextSettingsForOthers($serviceContext); return $this; } /** * PHP SDK currently only support XML for Object Serialization and Deserialization, except for Report Service * * @return $this */ public function useJson() { $serviceContext = $this->getServiceContext(); $serviceContext->useJson(); $this->updateServiceContextSettingsForOthers($serviceContext); return $this; } /** * Set a new directory for request and response log * * @param String $new_log_location The directory path for storing request and response log * * @return $this */ public function setLogLocation($new_log_location) { $restHandler = $this->restHandler; $loggerUsedByRestHandler = $restHandler->getRequestLogger(); $loggerUsedByRestHandler->setLogDirectory($new_log_location); return $this; } /** * Set logging for OAuth calls * * @param Boolean $enableLogs Turns on logging for OAuthCalls * * @param Boolean $debugMode Turns on debug mode to log tokens * * @param String $new_log_location The directory path for storing request and response log * * @return $this */ public function setLogForOAuthCalls($enableLogs, $debugMode, $new_log_location) { $this->OAuth2LoginHelper->setLogForOAuthCalls($enableLogs, $debugMode, $new_log_location); return $this; } /** * Set a new Minor Version * * @param String $newMinorVersion The new minor version that passed * * @return $this */ public function setMinorVersion($newMinorVersion) { $serviceContext = $this->getServiceContext(); $serviceContext->setMinorVersion($newMinorVersion); $this->updateServiceContextSettingsForOthers($serviceContext); return $this; } /** * Disable the logging function * * @return $this */ public function disableLog() { $restHandler = $this->restHandler; $loggerUsedByRestHandler = $restHandler->getRequestLogger(); $loggerUsedByRestHandler->setLogStatus(false); return $this; } /** * Enable the logging function * * @return $this */ public function enableLog() { $restHandler = $this->restHandler; $loggerUsedByRestHandler = $restHandler->getRequestLogger(); $loggerUsedByRestHandler->setLogStatus(true); return $this; } /** * Choose if want to throw exception when there is an non-200 http status code returned. * @param Boolean $bool Turn on exception throwing error or not */ public function throwExceptionOnError($bool){ $this->throwExceptionOnError = $bool; return $this; } /** * Return the settings for thrown exception on non-200 error code * @return Boolean Thrown Exception on Error or not */ public function isThrownExceptionOnError(){ return $this->throwExceptionOnError; } /** * Return the client Name used by this DataSerivce * @return String the Client Name. It can be curl or GuzzleHttpClient * @deprecated since version 5.0.4 * @see $this->getClientName() */ public function getClinetName(){ return $this->getClientName(); } /** * The client Name can be either 'curl', 'guzzle', or 'guzzlehttp'. * * @param String $clientName The client Name used by the service * * @return $this */ public function setClientName($clientName){ $this->clientName = $clientName; $serviceContext = $this->getServiceContext(); $this->setupRestHandler($serviceContext); return $this; } /** * New Static function for static Reading from Config or Passing Array * The config needs to include * * @param $settings * @return DataService * @throws SdkException * @throws SdkException */ public static function Configure($settings) { if (isset($settings)) { if (is_array($settings)) { $ServiceContext = ServiceContext::ConfigureFromPassedArray($settings); if (!isset($ServiceContext)) { throw new SdkException('Construct ServiceContext from OAuthSettigs failed.'); } $DataServiceInstance = new DataService($ServiceContext); } elseif (is_string($settings)) { $ServiceContext = ServiceContext::ConfigureFromLocalFile($settings); if (!isset($ServiceContext)) { throw new SdkException('Construct ServiceContext from File failed.'); } $DataServiceInstance = new DataService($ServiceContext); } if($ServiceContext->IppConfiguration->OAuthMode == CoreConstants::OAUTH2) { $oauth2Config = $ServiceContext->IppConfiguration->Security; if($oauth2Config instanceof OAuth2AccessToken){ $DataServiceInstance->configureOAuth2LoginHelper($oauth2Config, $settings); }else{ throw new SdkException("SDK Error. OAuth mode is not OAuth 2."); } } return $DataServiceInstance; } else { throw new SdkException("Passed Null to Configure method. It expects either a file path for the config file or an array containing OAuth settings and BaseURL."); } } /** * After the ServiceContext is complete, also set the LoginHelper based on the ServiceContext. * @param OAuth2AccessToken $oauth2Conifg OAuth 2 Token related information * @param Array $settings The array that include the redirectURL, scope, state information */ private function configureOAuth2LoginHelper($oauth2Conifg, $settings) { $refreshToken = CoreConstants::getRefreshTokenFromArray($settings); if(isset($refreshToken)){ //Login helper for refresh token API call $this->OAuth2LoginHelper = new OAuth2LoginHelper(null, null, null, null, null, $this->getServiceContext()); }else{ $redirectURL = CoreConstants::getRedirectURL($settings); $scope = array_key_exists('scope', $settings) ? $settings['scope'] : null; $state = array_key_exists('state', $settings) ? $settings['state'] : null; $this->OAuth2LoginHelper = new OAuth2LoginHelper($oauth2Conifg->getClientID(), $oauth2Conifg->getClientSecret(), $redirectURL, $scope, $state); } } /** * Return the OAuth 2 Login Helper. The OAuth 2 Login helper can be used to generate OAuth code, get refresh Token, etc. * @return $OAuth2LoginHelper A helper to get OAuth 2 related values. */ public function getOAuth2LoginHelper() { return $this->OAuth2LoginHelper; } /** * Update the OAuth 2 Token that will be used for API calls later. * * @param OAuth2AccessToken $newOAuth2AccessToken The OAuth 2 Access Token that will be used later. * * @return $this */ public function updateOAuth2Token($newOAuth2AccessToken) { try{ $this->serviceContext->updateOAuth2Token($newOAuth2AccessToken); $realmID = $newOAuth2AccessToken->getRealmID(); $this->serviceContext->realmId = $realmID; $this->setupRestHandler($this->serviceContext); } catch (SdkException $e){ $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Encountered an error while updating OAuth2Token." . $e->getMessage()); $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Stack Trace: " . $e->getTraceAsString()); } return $this; } /** * Get the error from last request * * @return FaultHandler lastError */ public function getLastError() { return $this->lastError; } /** * Setups serializers objects for responces and requests based on service context */ public function setupSerializers() { $this->responseSerializer = CoreHelper::GetSerializer($this->serviceContext, false); $this->requestSerializer = CoreHelper::GetSerializer($this->serviceContext, true); } private function useMinorVersion() { $version = $this->serviceContext->IppConfiguration->minorVersion; if (is_numeric($version) && !empty($version)) { $this->serviceContext->minorVersion = $version; } return $this; } /** * @return string */ public function getMinorVersion() { return $this->serviceContext->minorVersion; } /** * Force json serializers for request and response */ public function forceJsonSerializers() { $this->requestSerializer = new JsonObjectSerializer(); $this->responseSerializer = new JsonObjectSerializer(); } /** * Returns serializer for responce objects * @return IEntitySerializer */ protected function getResponseSerializer() { return $this->responseSerializer; } /** * Returns serializer for request objects * @return IEntitySerializer */ protected function getRequestSerializer() { return $this->requestSerializer; } /** * Marshall a POPO object to XML, presumably for inclusion on an IPP v3 API call * * * * @param object $phpObj inbound POPO object * @return string XML output derived from POPO object * @deprecated since version ? */ private function getXmlFromObj($phpObj) { if (!$phpObj) { $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "getXmlFromObj NULL arg."); return false; } $php2xml = new Php2Xml(CoreConstants::PHP_CLASS_PREFIX); $php2xml->overrideAsSingleNamespace = 'http://schema.intuit.com/finance/v3'; try { return $php2xml->getXml($phpObj); } catch (\Exception $e) { $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Encountered an error parsing Object to XML." . $e->getMessage()); $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Stack Trace: " . $e->getTraceAsString()); return false; } } /** * Decorate an IPP v3 Entity name (like 'Class') to be a POPO class name (like 'IPPClass') * * @param string Intuit Entity name * @return string POPO class name */ private static function decorateIntuitEntityToPhpClassName($intuitEntityName) { $className = CoreConstants::PHP_CLASS_PREFIX . $intuitEntityName; $className = trim($className); return $className; } //Since we add the namespace, this one needs to be changed as well. private static function getEntityResourceName($entity) { return strtolower(self::cleanPhpClassNameToIntuitEntityName(get_class($entity))); } /** * Clean a POPO class name (like 'IPPClass') to be an IPP v3 Entity name (like 'Class') * * @param string $phpClassName POPO class name * @return string|null Intuit Entity name */ private static function cleanPhpClassNameToIntuitEntityName($phpClassName) { $phpClassName = self::removeNameSpaceFromPhpClassName($phpClassName); if (0 == strpos($phpClassName, CoreConstants::PHP_CLASS_PREFIX)) { return substr($phpClassName, strlen(CoreConstants::PHP_CLASS_PREFIX)); } return null; } /** * Remove the Namespace from a php class name * * @param string $phpClassName QuickBooksOnline\API\Data\... * @return string ipp... */ private static function removeNameSpaceFromPhpClassName($phpClassName) { $lists = explode('\\', $phpClassName); $ippEntityName = end($lists); return $ippEntityName; } /** * Using the @entity and @uri to generate Request. * Response will parsed. It will store any Error Code in 3xx to 5xx level. * * @param IPPIntuitEntity $entity * @param string $uri * @param string $httpsPostBody * @param string $CALLINGMETHOD * @param string|null $boundaryString * @param string|null $email * @return null|string */ private function sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, $CALLINGMETHOD, $boundaryString = null, $email = null) { if ($this->isCreditCardPaymentTxn($entity)) { $uri = str_replace("creditcardpaymenttxn", "creditcardpayment", $uri); } switch ($CALLINGMETHOD) { case DataService::DELETE: case DataService::ADD: case DataService::VOID: case DataService::UPDATE: $requestParameters = $this->initPostRequest($entity, $uri); break; case DataService::FINDBYID: if ($this->serviceContext->IppConfiguration->Message->Request->SerializationFormat == SerializationFormat::Json) { $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONJSON, null); } else { $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); } break; case DataService::UPLOAD: if (!isset($boundaryString)) { throw new \Exception("Upload Image has unset value: boundaryString."); } // Creates request parameters $requestParameters = $this->getPostRequestParameters($uri, "multipart/form-data; boundary={$boundaryString}"); break; case DataService::SENDEMAIL: $requestParameters = $this->getPostRequestParameters($uri . (is_null($email) ? '' : '?sendTo=' . urlencode($email)), CoreConstants::CONTENTTYPE_OCTETSTREAM); break; } $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; if (strcmp($CALLINGMETHOD, DataService::ADD) == 0) { $responseBody = $this->fixTaxServicePayload($entity, $responseBody); } try { $parsedResponseBody = $this->getResponseSerializer()->Deserialize($responseBody, true); } catch (\Exception $e) { return new \Exception("Exception in deserialize ResponseBody."); } $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Finished Executing Method " . $CALLINGMETHOD); return $parsedResponseBody; } } /** * Updates an entity under the specified realm. The realm must be set in the context. * * @param IPPIntuitEntity $entity Entity to Update. * @return IPPIntuitEntity Returns an updated version of the entity with updated identifier and sync token. * @throws IdsException */ public function Update($entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method: Update."); // Validate parameter if (!$entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } $this->verifyOperationAccess($entity, __FUNCTION__); $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource); // Builds resource Uri // Handle some special cases if ((strtolower('preferences') == strtolower($urlResource)) && (CoreConstants::IntuitServicesTypeQBO == $this->serviceContext->serviceType) ) { // URL format for *QBO* prefs request is different than URL format for *QBD* prefs request $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource)); } //We no longer support QBD on PHP SDK The code is removed. /*else if ((strtolower('company') == strtolower($urlResource)) && (CoreConstants::IntuitServicesTypeQBO == $this->serviceContext->serviceType)) { // URL format for *QBD* companyinfo request is different than URL format for *QBO* companyinfo request $urlResource = 'companyInfo'; $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=update')); }*/ else { // Normal case $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=update')); } // Send Request and return response return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::UPDATE); } /** * The Read request. You can either pass an object that contains the Id that you want to read, or * pass the Entity Name and the Id. * Before v4.0.0, it supports the read of CompanyInfo and Preferences. * After v4.0.0, it DOES NOT support read of CompanyInfo or Preferences. Please use getCompanyInfo() or getCompanyPreferences() method instead. * Only use this one to do READ request with ID. * * Developer has two ways to call the GET request. Take Invoice for an example: * 1) FindById($invoice); * or * 2) FindById("invoice", 1); * * @param object|String $entity Entity to Find, or the String Name of the Entity * @return IPPIntuitEntity Returns an entity of specified Id. * @throws IdsException */ public function FindById($entity, $Id = null) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method FindById."); if(is_object($entity)){ $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource); // Validate parameter if (!$entity || !$entity->Id) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception when calling FindById for Endpoint:' . get_class($entity)); } $this->verifyOperationAccess($entity, __FUNCTION__); $entityId = $this->getIDString($entity->Id); // Normal case $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource, $entityId)); // Send request return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, null, DataService::FINDBYID); }else if(is_string($entity) && isset($Id)){ $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, strtolower($entity), $Id)); if ($this->isCreditCardPaymentTxn($entity)) { $uri = str_replace("creditcardpaymenttxn", "creditcardpayment", $uri); } $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { //clean the error $this->lastError = false; $parsedResponseBody = $this->getResponseSerializer()->Deserialize($responseBody, true); return $parsedResponseBody; } } } /** * Creates an entity under the specified realm. The realm must be set in the context. * * @param IPPIntuitEntity $entity Entity to Create. * @return IPPIntuitEntity Returns the created version of the entity. * @throws IdsException */ public function Add($entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Add."); // Validate parameter if (!$entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } $this->verifyOperationAccess($entity, __FUNCTION__); if ($this->isJsonOnly($entity)) { $this->forceJsonSerializers(); } $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource); // Builds resource Uri $resourceURI = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource)); $uri = $this->handleTaxService($entity, $resourceURI); // Send request return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::ADD); } /** * Deletes an entity under the specified realm. The realm must be set in the context. * * @param IPPIntuitEntity $entity Entity to Delete. * @return null|string * @throws IdsException */ public function Delete($entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Delete."); // Validate parameter if (!$entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } $this->verifyOperationAccess($entity, __FUNCTION__); // Builds resource Uri $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource); $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . '?operation=delete')); // Creates request return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::DELETE); } /** * Voids an entity under the specified realm. The realm must be set in the context. * * @param IPPIntuitEntity $entity Entity to Void. * @return null|string * @throws IdsException */ public function Void($entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Void."); // Validate parameter if (!$entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } $this->verifyOperationAccess($entity, __FUNCTION__); // Builds resource Uri $httpsPostBody = $this->executeObjectSerializer($entity, $urlResource); $className = $this->getEntityResourceName($entity); if(in_array($className, CoreConstants::PAYMENTCLASSNAME)) { $appendString = CoreConstants::VOID_QUERYPARAMETER_PAYMENT; } else{ $appendString = CoreConstants::VOID_QUERYPARAMETER_GENERAL; } $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource . $appendString)); // Creates request return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, $httpsPostBody, DataService::VOID); } /** * Uploads an attachment to an Entity on QuickBooks Online. For security reason, text file is not supported for uploading. * * @param string $bits Encoded Base64 bytes for the attachment * @param string $fileName Filename to use for this file * @param string $mimeType MIME type to send in the HTTP Headers * @param IPPAttachable $objAttachable Entity including the attachment, it can be invoice, bill, etc * @return array Returns an array of entities fulfilling the query. * @throws IdsException */ public function Upload($imgBits, $fileName, $mimeType, $objAttachable) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Upload."); // Validate parameter if (!$imgBits || !$mimeType || !$fileName) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } // Builds resource Uri $urlResource = "upload"; $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, $urlResource)); $boundaryString = md5(time()); $MetaData = $this->executeObjectSerializer($objAttachable, $urlResource); $desiredIdentifier = '0'; $newline = "\r\n"; $dataMultipart = ''; $dataMultipart .= '--' . $boundaryString . $newline; $dataMultipart .= "Content-Disposition: form-data; name=\"file_metadata_{$desiredIdentifier}\"" . $newline; $dataMultipart .= "Content-Type: " . CoreConstants::CONTENTTYPE_APPLICATIONXML . '; charset=UTF-8' . $newline; $dataMultipart .= 'Content-Transfer-Encoding: 8bit' . $newline . $newline; $dataMultipart .= $MetaData; $dataMultipart .= '--' . $boundaryString . $newline; $dataMultipart .= "Content-Disposition: form-data; name=\"file_content_{$desiredIdentifier}\"; filename=\"{$fileName}\"" . $newline; $dataMultipart .= "Content-Type: {$mimeType}" . $newline; $dataMultipart .= 'Content-Transfer-Encoding: base64' . $newline . $newline; $dataMultipart .= chunk_split($imgBits) . $newline; $dataMultipart .= "--" . $boundaryString . "--" . $newline . $newline; // finish with two eol's!! return $this->sendRequestParseResponseBodyAndHandleHttpError(null, $uri, $dataMultipart, DataService::UPLOAD, $boundaryString); } /** * Returns PDF for entities which can be downloaded as PDF * @param IPPIntuitEntity $entity * @param Directory a writable directory for the PDF to be saved. * @return boolean * @throws IdsException, SdkException * */ public function DownloadPDF($entity, $dir=null, $returnPdfString = false) { $this->validateEntityId($entity); $this->verifyOperationAccess($entity, __FUNCTION__); //Find the ID $entityID = $this->getIDString($entity->Id); $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, self::getEntityResourceName($entity), $entityID, CoreConstants::getType(CoreConstants::CONTENTTYPE_APPLICATIONPDF))); $requestParameters = $this->getGetRequestParameters($uri, CoreConstants::CONTENTTYPE_APPLICATIONPDF); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; //Add allow for through exception if users set it up return null; } elseif ($returnPdfString) { return $responseBody; } else { $this->lastError = false; return $this->processDownloadedContent(new ContentWriter($responseBody), $responseCode, $dir, $this->getExportFileNameForPDF($entity, "pdf")); } } /** * Sends entity by email for entities that have this operation * * @param IPPIntuitEntity $entity * @param string|null $email * @return boolean * @throws IdsException, SdkException * */ public function SendEmail($entity, $email = null) { $this->validateEntityId($entity); $this->verifyOperationAccess($entity, __FUNCTION__); $entityId=$this->getIDString($entity->Id); $uri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, self::getEntityResourceName($entity), $entityId, 'send')); if (is_null($email)) { $this->logInfo("Entity " . get_class($entity) . " with id=" . $entityId . " is using default email"); } else { $this->logInfo("Entity " . get_class($entity) . " with id=" . $entityId . " is using $email"); if (!$this->verifyEmailAddress($email)) { $this->logError("Valid email is expected, but received $email"); throw new SdkException("Valid email is expected, but received $email"); } } return $this->sendRequestParseResponseBodyAndHandleHttpError($entity, $uri, null, DataService::SENDEMAIL, null, $email); } /** * Retrieves specified entities based passed page number and page size and query * * @param string $query Query to issue * @param int $startPosition Starting page number * @param int $maxResults Page size * @param string $includes A list of additional fields requested in the entities response * @return array Returns an array of entities fulfilling the query. If the response is Empty, it will return NULL */ public function Query($query, $startPosition = null, $maxResults = null, $includes = null) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Query."); if ('QBO' == $this->serviceContext->serviceType) { $httpsContentType = CoreConstants::CONTENTTYPE_APPLICATIONTEXT; } else { $httpsContentType = CoreConstants::CONTENTTYPE_TEXTPLAIN; } $httpsUri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'query')); $httpsPostBody = $this->appendPaginationInfo($query, $startPosition, $maxResults); if(!is_null($includes)) { $httpsUri .= "?include=$includes"; } $requestParameters = $this->getPostRequestParameters($httpsUri, $httpsContentType); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $parsedResponseBody = null; try { $responseXmlObj = simplexml_load_string($responseBody); if ($responseXmlObj && $responseXmlObj->QueryResponse) { $tmpXML = $responseXmlObj->QueryResponse->asXML(); $parsedResponseBody = $this->responseSerializer->Deserialize($tmpXML, false); $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, $parsedResponseBody); } } catch (\Exception $e) { throw new \Exception("Exception appears in converting Response to XML."); } return $parsedResponseBody; } } /** * Append the Pagination Data to the Query string if it is not appended * @param Integer StartPostion * @param Integer MaxResults * @return String The query string */ private function appendPaginationInfo($query, $startPosition, $maxResults){ $query = trim($query); if(isset($startPosition) && !empty($startPosition)){ if(stripos($query, "STARTPOSITION") === false){ if(stripos($query, "MAXRESULTS") !== false){ //In MaxResult is defined,we don't set startPosition }else{ $query = $query . " " . "STARTPOSITION " . $startPosition; } }else{ //Ignore the startPosition if it is already used on the query } } if(isset($maxResults) && !empty($maxResults)){ if(stripos($query, "MAXRESULTS") === false){ $query = $query . " " . "MAXRESULTS " . $maxResults; }else{ //Ignore the maxResults if it is already used on the query } } return $query; } /** * Retrieves all entities by name * * @param string $entityName * @param int $pageNumber * @param int $pageSize * @return array Returns an array of entities of specified type. */ public function FindAll($entityName, $pageNumber = 0, $pageSize = 500) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method FindAll."); $phpClassName = DataService::decorateIntuitEntityToPhpClassName($entityName); // Handle some special cases if (strtolower('company') == strtolower($entityName)) { $entityName = 'CompanyInfo'; } if ('QBO' == $this->serviceContext->serviceType) { $httpsContentType = CoreConstants::CONTENTTYPE_APPLICATIONTEXT; } else { $httpsContentType = CoreConstants::CONTENTTYPE_TEXTPLAIN; } $httpsUri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'query')); $httpsPostBody = "select * from $entityName startPosition $pageNumber maxResults $pageSize"; $requestParameters = $this->getPostRequestParameters($httpsUri, $httpsContentType); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $parsedResponseBody = null; try { $responseXmlObj = simplexml_load_string($responseBody); if ($responseXmlObj && $responseXmlObj->QueryResponse) { $parsedResponseBody = $this->responseSerializer->Deserialize($responseXmlObj->QueryResponse->asXML(), false); } } catch (\Exception $e) { throw new \Exception("Exception appears in converting Response to XML."); } return $parsedResponseBody; } } /** * Returns List of entities changed after certain time. * * @param array entityList List of entity. * @param long changedSince DateTime of timespan after which entities were changed. * @return IntuitCDCResponse Returns an IntuitCDCResponse. */ public function CDC($entityList, $changedSince) { $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Called Method CDC."); // Validate parameter if (count($entityList) <= 0) { $exception = new IdsException('ParameterNotNullMessage'); $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "ParameterNotNullMessage"); IdsExceptionManager::HandleException($exception); } $entityString = implode(",", $entityList); $query = null; $uri = null; if(is_string($changedSince)){ $formattedChangedSince = trim($changedSince); }else{ $formattedChangedSince = date("Y-m-d\TH:i:s", $this->verifyChangedSince($changedSince)); } $query = "entities=" . $entityString . "&changedSince=" . $formattedChangedSince; $uri = "company/{1}/cdc?{2}"; //$uri = str_replace("{0}", CoreConstants::VERSION, $uri); $uri = str_replace("{1}", $this->serviceContext->realmId, $uri); $uri = str_replace("{2}", $query, $uri); // Creates request parameters $requestParameters = $this->getGetRequestParameters($uri, CoreConstants::CONTENTTYPE_APPLICATIONXML); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $returnValue = new IntuitCDCResponse(); try { $xmlObj = simplexml_load_string($responseBody); $responseArray = $xmlObj->CDCResponse->QueryResponse; if(sizeof($responseArray) != sizeof($entityList)){ throw new ServiceException("The number of Entities requested on CDC does not match the number of Response."); } for($i = 0; $i < sizeof($responseArray); $i++){ $currentResponse = $responseArray[$i]; $currentEntityName = $entityList[$i]; $entities = $this->responseSerializer->Deserialize($currentResponse->asXML(), false); $entityName = $currentEntityName; //If we find the actual name, update it. foreach ($currentResponse->children() as $currentResponseChild) { $entityName = (string)$currentResponseChild->getName(); break; } $returnValue->entities[$entityName] = $entities; } } catch (\Exception $e) { IdsExceptionManager::HandleException($e); } $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Method CDC."); return $returnValue; } } /** * Creates a RecurringTransaction Entity under the specified realm. The realm must be set in the context. * * @param IPPIntuitEntity $entity Entity to Create. * @return IntuitRecurringTransactionResponse Returns the RecurringTransaction created for the entity. * @throws IdsException */ public function addRecurringTxn($entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Add."); // Validate parameter if (!$entity) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } // Verify operation access $this->verifyOperationAccess($entity, __FUNCTION__); if ($this->isJsonOnly($entity)) { $this->forceJsonSerializers(); } // Create recurring transaction object $recurringtxn = RecurringTransactionAdapter::createRecurringTransactionObject($entity); // Create recurring transaction Post Body $httpsPostBody = RecurringTransactionAdapter::getRecurringTxnBody($recurringtxn); // Builds resource Uri $resourceURI = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'recurringtransaction')); $requestParameters = new RequestParameters($resourceURI, 'POST', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $returnValue = new IntuitRecurringTransactionResponse(); try { $xmlObj = simplexml_load_string($responseBody); // deserialize the response body $deserializedResponse = $this->responseSerializer->Deserialize($xmlObj->RecurringTransaction->asXML(), false); $entityName = XmlObjectSerializer::cleanPhpClassNameToIntuitEntityName(get_class($entity)); $returnValue->entities[$entityName] = $deserializedResponse; } catch (\Exception $e) { IdsExceptionManager::HandleException($e); } $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Recurring Transaction."); return $returnValue; } } /** * Query RecurringTransaction Entity under the specified realm. The realm must be set in the context. * * @param query ex : SELECT * FROM RecurringTransaction * @return IntuitRecurringTransactionResponse Returns the RecurringTransaction created for the entity. * @throws IdsException */ public function recurringTransaction($query) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Query."); if ('QBO' == $this->serviceContext->serviceType) { $httpsContentType = CoreConstants::CONTENTTYPE_APPLICATIONTEXT; } else { $httpsContentType = CoreConstants::CONTENTTYPE_TEXTPLAIN; } $httpsUri = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'query')); $httpsPostBody = $this->appendPaginationInfo($query, $startPosition, $maxResults); $requestParameters = $this->getPostRequestParameters($httpsUri, $httpsContentType); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $returnValue = new IntuitRecurringTransactionResponse(); try { $xmlObj = simplexml_load_string($responseBody); $responseArray = $xmlObj->QueryResponse->RecurringTransaction; if(sizeof($responseArray) <= 0){ throw new ServiceException("No recurring transactions found."); } for($i = 0; $i < sizeof($responseArray); $i++){ $currentResponse = $responseArray[$i]; $currentEntityName = $entityList[$i]; $entities = $this->responseSerializer->Deserialize($currentResponse->asXML(), false); $entityName = $currentEntityName; //If we find the actual name, update it. foreach ($currentResponse->children() as $currentResponseChild) { $entityName = (string)$currentResponseChild->getName(); break; } $returnValue->entities[$entityName][] = $entities; } } catch (\Exception $e) { IdsExceptionManager::HandleException($e); } $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Recurring Transaction."); return $returnValue; } } /** * Find a RecurringTransaction Entity By ID under the specified realm. The realm must be set in the context. * * @param $Id Id of the IPPIntuitEntity Object * @return IntuitRecurringTransactionResponse Returns the RecurringTransaction created for the entity. * @throws IdsException */ public function findRecurringTransactionById($Id = null) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method findRecurringTransactionById."); if (!$Id) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument [Id] Null Exception'); } // Builds resource Uri $resourceURI = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'recurringtransaction/'. $Id)); // Make the GET request to fetch the recurring transaction $requestParameters = new RequestParameters($resourceURI, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { //clean the error $this->lastError = false; $returnValue = new IntuitRecurringTransactionResponse(); try { $xmlObj = simplexml_load_string($responseBody); // deserialize the response body $deserializedResponse = $this->responseSerializer->Deserialize($xmlObj->RecurringTransaction->asXML(), false); $entityName = XmlObjectSerializer::cleanPhpClassNameToIntuitEntityName(get_class($deserializedResponse[0])); $returnValue->entities[$entityName] = $deserializedResponse; } catch (\Exception $e) { IdsExceptionManager::HandleException($e); } $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Recurring Transaction."); return $returnValue; } } /** * Find a RecurringTransaction Entity By ID under the specified realm. The realm must be set in the context. * * @param IntuitRecurringTransactionResponse RecurringTransaction Response from findRecurringTransactionById method. * @return IntuitRecurringTransactionResponse Returns the RecurringTransaction created for the entity. * @throws IdsException */ public function deleteRecurringTransaction($recurringTransaction) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, "Called Method Delete."); // Validate parameter if (!$recurringTransaction) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, "Argument Null Exception"); throw new IdsException('Argument Null Exception'); } $this->verifyOperationAccess($recurringTransaction, __FUNCTION__); // Get the Entity Name from $recurringTransaction $entityName = array_keys($recurringTransaction->entities)[0]; // Get the IPPEntity Object from $recurringTransaction $entity = $recurringTransaction->entities[$entityName][0]; // Create recurring transaction object $recurringtxn = RecurringTransactionAdapter::createRecurringTransactionObject($entity); // Create recurring transaction Post Body $httpsPostBody = RecurringTransactionAdapter::getRecurringTxnBody($recurringtxn); // Builds resource Uri $resourceURI = implode(CoreConstants::SLASH_CHAR, array('company', $this->serviceContext->realmId, 'recurringtransaction' . '?operation=delete')); // Make the GET request to fetch the recurring transaction $requestParameters = new RequestParameters($resourceURI, 'POST', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { //clean the error $this->lastError = false; $returnValue = new IntuitRecurringTransactionResponse(); try { $xmlObj = simplexml_load_string($responseBody); // deserialize the response body $deserializedResponse = $this->responseSerializer->Deserialize($xmlObj->RecurringTransaction->asXML(), false); $entityName = XmlObjectSerializer::cleanPhpClassNameToIntuitEntityName(get_class($entity)); $returnValue->entities[$entityName] = $deserializedResponse; } catch (\Exception $e) { IdsExceptionManager::HandleException($e); } $this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Executing Recurring Transaction."); return $returnValue; } } /** * Returns an entity under the specified realm. The realm must be set in the context. * * @param object $entity Entity to Find * @return IPPIntuitEntity Returns an entity of specified Id. */ public function Retrieve($entity) { $this->verifyOperationAccess($entity, __FUNCTION__); return $this->FindById($entity); } /** * Serializes oblect into specified format * @param IPPIntuitEntity $entity * @param String $urlResource * @return object */ protected function executeObjectSerializer($entity, &$urlResource) { $result = $this->getRequestSerializer()->Serialize($entity); $urlResource = $this->getRequestSerializer()->getResourceURL(); return $result; } /** * Returns post request, depends on configuration and entity rule "jsonOnly" * @param IPPIntuitEntity $entity * @param string $uri * @return RequestParameters */ protected function initPostRequest($entity, $uri) { return $this->isJsonOnly($entity) ? $this->getPostJsonRequest($uri) : $this->getPostRequest($uri); } /** * Returns content type depends from serialization format * @return string */ private function getContentType() { return ($this->getSerializationFormat() == SerializationFormat::Json) ? CoreConstants::CONTENTTYPE_APPLICATIONJSON : CoreConstants::CONTENTTYPE_APPLICATIONXML; } /** * Returns post request with pre-defined POST method and JSON serialization * @param string $uri * @return RequestParameters */ private function getPostJsonRequest($uri) { return $this->getPostRequestParameters($uri, CoreConstants::CONTENTTYPE_APPLICATIONJSON); } /** * Return true if specified entity can work with JSON only serialization * @param IPPIntuitEntity $entity * @return boolean */ private function isJsonOnly($entity) { return $this->isAllowed($entity, "jsonOnly"); } /** * Returns pre-defined request with POST method and content type from settings * @param string $uri * @return RequestParameters */ private function getPostRequest($uri) { return $this->getPostRequestParameters($uri, $this->getContentType()); } /** * Returns pre-defined request with GET method * @param string $uri * @param string $type * @return RequestParameters */ private function getGetRequestParameters($uri, $type) { return $this->getRequestParameters($uri, 'GET', $type); } /** * Returns pre-defined request with POST method * @param string $uri * @param string $type * @return RequestParameters */ private function getPostRequestParameters($uri, $type) { return $this->getRequestParameters($uri, 'POST', $type); } /** * Wraps and returns RequestParameters object * @param string $uri * @param string $method * @param string $type * @param string $apiName * @return RequestParameters */ protected function getRequestParameters($uri, $method, $type, $apiName = null) { return new RequestParameters($uri, $method, $type, $apiName); } /** * Returns current serialization format * * @return string */ protected function getSerializationFormat() { return $this->serviceContext->IppConfiguration->Message->Request->SerializationFormat; } /** * Handles unusual URL mapping for TaxService * @param IPPIntuitEntity $entity * @param string $uri * @return string */ private function handleTaxService($entity, $uri) { if ($this->isTaxServiceSafe($entity)) { return $uri . '/taxcode'; } return $uri; } /** * Verifies that entity has TaxService type * update the TaxService with namespace added * If this class is not available on include_path or wab't loaded the method will return false * * @param IPPTaxService $entity * @return bool */ private function isTaxServiceSafe($entity) { $IPPTaxServiceClassWIthNameSpace = "QuickBooksOnline\\API\\Data\\IPPTaxService"; return class_exists($IPPTaxServiceClassWIthNameSpace) && ($entity instanceof $IPPTaxServiceClassWIthNameSpace); } private function isCreditCardPaymentTxn($entity) { $IPPCreditCardPaymentTxnClass = "QuickBooksOnline\\API\\Data\\IPPCreditCardPaymentTxn"; if (class_exists($IPPCreditCardPaymentTxnClass) && ($entity instanceof $IPPCreditCardPaymentTxnClass)) return true; else if (is_string($entity) && $entity == "CreditCardPaymentTxn") return true; return false; } /** * Methods provides workaround to successfully process TaxService response * @param $entity * @param $content * @return string */ private function fixTaxServicePayload($entity, $content) { if ($this->isTaxServiceSafe($entity)) { //get first "line" to make sure we don't have TaxService in response $sample = substr(trim($content), 0, 20); $taxServiceName = self::cleanPhpClassNameToIntuitEntityName(get_class($entity)); if (false === strpos($sample, $taxServiceName)) { //last attempt to verify content before if (0 === strpos($sample, '{"TaxCode":')) { return "{\"$taxServiceName\":$content}"; } } } return $content; } /** * Returns an downloaded entity under the specified realm. The realm must be set in the context. * * @param object $entity Entity to Find * @return string IPPIntuitEntity Returns an entity of specified Id. * @deprecated The download for QuickBooksOnline is only supporting download PDF for Invoice and SalesReceipt. Other download function are not defined now. */ public function Download($entity) { return $this->FindById($entity); } /** * Verifies string as email agains RFC 822 * @param string $email * @return type */ public function verifyEmailAddress($email) { return filter_var($email, FILTER_VALIDATE_EMAIL); } /** * Returns PDF filename based on entity type and id * @param IPPIntuitEntity $entity * @param string $ext * @return string */ public function getExportFileNameForPDF($entity, $ext, $usetimestamp = true) { //TODO: add timestamp or GUID $this->validateEntityId($entity); return self::getEntityResourceName($entity) . "_" . $this->getIDString($entity->Id) . ($usetimestamp ? "_" . time() : "") . ".$ext"; } /** * Returns the Sync Resthandler associated with the dataserivce * @return SyncRestHandler The SyncRestHandler with the DataService */ protected function getRestHandler() { if(isset($this->restHandler)){ return $this->restHandler; }else{ throw new SdkException("The SyncRest handler associated with the DataService is not set."); } } /** * Saves exported (e.g. check DownloadPDF) entity into file according to strategy in settings * @param ContentWriter $writer * @param int $responseCode * @param string $fileName * @return mixed full path with filename or open handler */ protected function processDownloadedContent(ContentWriter $writer, $responseCode, $dir, $fileName = null) { $writer->setPrefix($this->getPrefixFromSettings()); try { if(isset($dir) && !empty($dir)){ $writer->saveFile($dir, $fileName); }else if ($this->isTempFile()) { $writer->saveTemp(); } elseif ($this->isFileExport()) { $writer->saveFile($this->getFileExportDir(), $fileName); } else { $writer->saveAsHandler(); } //return object as is if ($this->isReturnContentWriter()) { return $writer; } $writer->resetContent(); $this->logInfo("File was downloaded (http response = $responseCode), bytes written: {$writer->getBytes()}"); } catch (\Exception $ex) { $this->logError("Exception appears during response processing. Http response was $responseCode: " . $ex->getMessage() . "\n" . $ex->getTraceAsString()); return null; } return $writer->isHandler() ? $writer->getHandler() : $writer->getTempPath(); } protected function processRecurringTransactionResponse($recurringTransaction) { //Return an array of objects $entities = []; foreach ($recurringTransaction as $oneResponse) { $oneEntity = $this->responseSerializer->Deserialize('<RestResponse>'.$oneResponse->children()->asXML().'</RestResponse>'); $entities = array_merge($entities, $oneEntity); } return $entities; } /** * Returns true or false if writer object is allowed as return result * @return boolean */ private function isReturnContentWriter() { return $this->serviceContext->IppConfiguration->ContentWriter->returnOject; } /** * Returns prefix for contentWriter * @return string */ private function getPrefixFromSettings() { return $this->serviceContext->IppConfiguration->ContentWriter->prefix; } /** * Returns true if SDK is configured to save temporary files * @return boolean */ private function isTempFile() { return (CoreConstants::FILE_STRATEGY === $this->serviceContext->IppConfiguration->ContentWriter->strategy); } /** * Returns true if SDK is configured to export files to another location * @return boolean */ private function isFileExport() { return (CoreConstants::EXPORT_STRATEGY === $this->serviceContext->IppConfiguration->ContentWriter->strategy); } /** * Returns path to directory where SDK should save files * @return string */ private function getFileExportDir() { return $this->serviceContext->IppConfiguration->ContentWriter->exportDir; } /** * Simple verification for entities which can be returned as PDF */ private function isAllowed($entity, $method) { $className = get_class($entity); if (!$className) { $this->logError("Intuit entity is expected here instead of $entity"); throw new IdsException('Unexpected Argument Exception'); } $classArray = explode('\\', $className); $trimedClassName = end($classArray); return $this->serviceContext->IppConfiguration->OpControlList->isAllowed($trimedClassName, $method); } private function verifyOperationAccess($entity, $func) { if (!$this->isAllowed($entity, $func)) { $this->logError("Cannot invoke " . $func . " for \"" . get_class($entity) . "\" because of operation contstrains."); throw new IdsException('Operation ' . $func . ' is not allowed for entity ' . get_class($entity)); } return true; } private function validateEntityId($entity) { if (empty($entity)) { $this->logError("Argument Null Exception"); throw new IdsException('Argument Null Exception'); } if (!isset($entity->Id)) { $this->logError("Property ID doesn't exist"); throw new IdsException('Property ID is not set'); } if (empty($entity->Id)) { $this->logError("Property ID is empty"); throw new IdsException('Property ID is empty'); } return true; } private function logError($message) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Error, $message); } private function logInfo($message) { $this->serviceContext->IppConfiguration->Logger->RequestLog->Log(TraceLevel::Info, $message); } /** * Creates new batch * * @return Batch returns the batch object */ public function CreateNewBatch() { $batch = new Batch($this->serviceContext, $this->getRestHandler(), $this->isThrownExceptionOnError()); return $batch; } /** * Parse input date-time string into unix timestamp * @param string $str * @return int timestamp or false overwise * @throws SdkException */ private function convertToTimestamp($str) { $result = date_parse($str); if (!$result) { return false; } if (empty($result) || !is_array($result)) { return false; } extract($result); if (!empty($errors)) { throw new SdkException("SDK failed to parse date value \"$str\":" . (is_array($errors) ? implode("\n", $errors) : $errors) ); } //@TODO: mktime is deprecated since 5.3.0, this package needs 5.6 return mktime($hour, $minute, $second, $month, $day, $year); } /** * Checks if input string is a valid timestamp or not * @param string timestamp contains input timestamp-like string * @return bool */ public function isValidTimeStamp($timestamp) { return ((string)(int)$timestamp === $timestamp) && ($timestamp <= PHP_INT_MAX) && ($timestamp >= ~PHP_INT_MAX); } /** * Verifies input and returns unix timestamp * @param mixed $value * @return int * @throws SdkException */ protected function verifyChangedSince($value) { if (is_int($value)) { return $value; } // remove whitespaces, tabulation etc $trimmed = trim($value); if ($this->isValidTimeStamp($trimmed)) { return $trimmed; } //at this point we have numeric string which is not timestamp if (is_numeric($value)) { throw new SdkException("Input string doesn't look as unix timestamp or date string"); } // trying to parse string into timestamp $converted = $this->convertToTimestamp($value); if (!$converted) { throw new SdkException("Input value should be unix timestamp or valid date string"); } return $converted; } /** * Get the Company Information * @return IPPCompanyInfo CompanyInformation */ public function getCompanyInfo() { $currentServiceContext = $this->getServiceContext(); if (!isset($currentServiceContext) || empty($currentServiceContext->realmId)) { throw new SdkException("Please Setup Service Context before making get CompanyInfo call."); } //The CompanyInfo URL $uri = implode(CoreConstants::SLASH_CHAR, array('company', $currentServiceContext->realmId, 'companyinfo', $currentServiceContext->realmId)); $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $parsedResponseBody = $this->getResponseSerializer()->Deserialize($responseBody, true); return $parsedResponseBody; } } /** * Get the Company Preferences Information * @return IPPPreferences CompanyInformation */ public function getCompanyPreferences() { $currentServiceContext = $this->getServiceContext(); if (!isset($currentServiceContext) || empty($currentServiceContext->realmId)) { throw new SdkException("Please Setup Service Context before making get Company Preferences call."); } //The Preferences URL $uri = implode(CoreConstants::SLASH_CHAR, array('company', $currentServiceContext->realmId, 'preferences')); $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, null, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; $parsedResponseBody = $this->getResponseSerializer()->Deserialize($responseBody, true); return $parsedResponseBody; } } /** * Get the Entitlement Response * @return \SimpleXMLElement Xml */ public function getEntitlementsResponse() { $currentServiceContext = $this->getServiceContext(); if (!isset($currentServiceContext) || empty($currentServiceContext->realmId)) { throw new SdkException("Please Setup Service Context before making get entitlements response call."); } //The Preferences URL $uri = $this->getServiceContext()->IppConfiguration->BaseUrl->Qbo; $requestParameters = new RequestParameters($uri, 'GET', CoreConstants::CONTENTTYPE_APPLICATIONXML, null); $restRequestHandler = $this->getRestHandler(); $entitlementsUri = $this->getServiceContext()->IppConfiguration->BaseUrl->Qbo . "manage/entitlements/v3/" . $this->serviceContext->realmId; list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, null, $entitlementsUri, $this->isThrownExceptionOnError()); $faultHandler = $restRequestHandler->getFaultHandler(); //$faultHandler now is true or false if ($faultHandler) { $this->lastError = $faultHandler; return null; } else { $this->lastError = false; return simplexml_load_string($responseBody); } } /** * Get the actual ID string value of either an IPPid object, or an Id string * @param Object $id * @return String Id */ private function getIDString($id){ if($id instanceof IPPid){ return (String)$id->value; }else{ return (String)$id; } } }
Copyright ©2021 || Defacer Indonesia