%PDF- %GIF98; %PNG;
Server : ApacheSystem : Linux host.digitalbabaji.in 4.18.0-513.11.1.el8_9.x86_64 #1 SMP Wed Jan 17 02:00:40 EST 2024 x86_64 User : addictionfreeind ( 1003) PHP Version : 7.2.34 Disable Function : exec,passthru,shell_exec,system Directory : /home/addictionfreeind/public_html/admin1/vendor/quickbooks/v3-php-sdk/src/DataService/ |
Upload File : |
<?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\Http\Serialization\XmlObjectSerializer;
use QuickBooksOnline\API\Exception\IdsExceptionManager;
use QuickBooksOnline\API\Exception\IdsException;
use QuickBooksOnline\API\Exception\IdsError;
use QuickBooksOnline\API\Exception\ValidationException;
use QuickBooksOnline\API\Exception\ServiceException;
use QuickBooksOnline\API\Exception\SecurityException;
use QuickBooksOnline\API\Core\CoreHelper;
use QuickBooksOnline\API\Core\ServiceContext;
use QuickBooksOnline\API\Core\HttpClients\FaultHandler;
use QuickBooksOnline\API\Core\HttpClients\RestHandler;
use QuickBooksOnline\API\Data\IPPBatchItemRequest;
use QuickBooksOnline\API\Data\IPPIntuitBatchRequest;
use QuickBooksOnline\API\Core\CoreConstants;
use QuickBooksOnline\API\Core\HttpClients\SyncRestHandler as RestServiceSyncRestHandler;
use QuickBooksOnline\API\Diagnostics\TraceLevel;
use QuickBooksOnline\API\Core\HttpClients\RequestParameters;
use QuickBooksOnline\API\Utility\UtilityConstants;
use \QuickBooksOnline\API\Core\Http\Serialization\IEntitySerializer;
/**
* This class contains code for Batch Processing.
*/
class Batch
{
/**
* batch requests
* @var array batchRequests
*/
private $batchRequests;
/**
* batch responses
* @deprecated
* @var array batchResponses
*/
private $batchResponses;
/**
* Intuit batch item responses list.
* @var array batchResponses
*/
public $intuitBatchItemResponses;
/**
* service context object.
* @var ServiceContext serviceContext
*/
private $serviceContext;
/**
* rest handler object.
* @var RestHandler restHandler
*/
private $restHandler;
/**
* serializer to be used.
* @var IEntitySerializer responseSerializer
*/
private $responseSerializer;
/**
* If not false, the request from last dataService did not return 2xx
* @var FaultHandler
*/
private $lastError = false;
/**
* Throw Exception on Error or not. Default is false.
* @var boolean
*/
private $isThrowExceptionOnError = false;
/**
* Enable debug mode to get more information inside the exception like intuit-tid
* @var boolean
*/
private $debugMode = false;
/**
* Get the error from last request
* @return FaultHandler
*/
public function getLastError()
{
return $this->lastError;
}
/**
* Set the debug mode
* @param $mode
*/
public function setDebug($mode)
{
$this->debugMode = $mode;
}
/**
* Initializes a new instance of the Batch class.
* @param $serviceContext The service context.
* @param $restHandler The rest handler.
*/
public function __construct($serviceContext, $restHandler, $isThrowExceptionOnError)
{
$this->serviceContext = $serviceContext;
$this->restHandler = $restHandler;
$this->isThrowExceptionOnError = $isThrowExceptionOnError;
$this->responseSerializer = CoreHelper::GetSerializer($this->serviceContext, false);
$this->batchRequests = array();
$this->batchResponses = array();
$this->intuitBatchItemResponses = array();
}
/**
* Gets the count.
* @return int count
*/
public function Count()
{
return count($this->batchRequests);
}
/**
* Gets list of entites in case ResponseType is Report.
*/
public function ReadOnlyCollection()
{
return $this->intuitBatchItemResponses;
}
/**
* Gets the IntuitBatchResponse with the specified id.
* @param string $id unique batchitem id
*/
public function IntuitBatchResponse($id)
{
if(array_key_exists($id, $this->intuitBatchItemResponses)){
return $this->intuitBatchItemResponses[$id];
}else{
return null;
}
}
/**
* Adds the specified query.
* @param string $query IDS query.
* @param string $id unique batchitem id.
*/
public function AddQuery($query, $id)
{
if (!$query) {
$exception = new IdsException('StringParameterNullOrEmpty: query');
IdsExceptionManager::HandleException($exception);
}
if (!$id) {
$exception = new IdsException('StringParameterNullOrEmpty: id');
IdsExceptionManager::HandleException($exception);
}
if (count($this->batchRequests)>25) {
$exception = new IdsException('BatchItemsExceededException');
IdsExceptionManager::HandleException($exception);
}
$batchItem = new IPPBatchItemRequest();
$batchItem->Query = $query;
$batchItem->bId = $id;
$batchItem->operationSpecified = true;
//$batchItem->ItemElementName = ItemChoiceType6::Query;
$this->batchRequests[] = $batchItem;
}
/**
* Adds the specified query.
* @param IEntity entity entitiy for the batch operation.
* @param string id Unique batchitem id
* @param OperationEnum operation operation to be performed for the entity.
* @param string optionsdata to send with this specific batch item (example - allowduplicatedocnumber for invoices)
*/
public function AddEntity($entity, $id, $operation, $optionsData = null)
{
if (!$entity) {
$exception = new IdsException('StringParameterNullOrEmpty: entity');
IdsExceptionManager::HandleException($exception);
}
if (!$id) {
$exception = new IdsException('StringParameterNullOrEmpty: id');
IdsExceptionManager::HandleException($exception);
}
if (!$operation) {
$exception = new IdsException('StringParameterNullOrEmpty: operation');
IdsExceptionManager::HandleException($exception);
}
foreach ($this->batchRequests as $oneBatchRequest) {
if ($oneBatchRequest->bId == $id) {
$exception = new IdsException('BatchIdAlreadyUsed');
IdsExceptionManager::HandleException($exception);
}
}
$batchItem = new IPPBatchItemRequest();
$batchItem->IntuitObject = $entity;
$batchItem->bId = $id;
$batchItem->operation = $operation;
$batchItem->operationSpecified = true;
if ($optionsData !== null) {
$batchItem->optionsData = $optionsData;
}
$this->batchRequests[] = $batchItem;
}
/**
* Removes batchitem with the specified batchitem id.
* @param string id unique batchitem id
*/
public function Remove($id)
{
if (!$id) {
$exception = new IdsException('BatchItemIdNotFound: id');
IdsExceptionManager::HandleException($exception);
}
$revisedBatchRequests = array();
foreach ($this->batchRequests as $oneBatchRequest) {
if ($oneBatchRequest->bId == $id) {
// Exclude
} else {
$revisedBatchRequests[] = $oneBatchRequest;
}
}
$this->batchRequests = $revisedBatchRequests;
}
/**
* Remove all the batchitem requests.
*/
public function RemoveAll()
{
$this->batchRequests = array();
}
/**
* This method executes the batch request.
*/
public function Execute()
{
$requestID = rand() . rand();
$this->sendRequest($requestID);
}
/**
* Use this function to do Batch Request instead of Execute()
*/
public function ExecuteWithRequestID($requestID)
{
if(isset($requestID) && !empty($requestID)){
$this->sendRequest($requestID);
}else{
throw new \Exception("ExecuteWithRequestID called with Empty or Null request ID");
}
}
private function sendRequest($requestID)
{
$this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Started Executing Method Execute for Batch");
// Create Intuit Batch Request
$intuitBatchRequest = new IPPIntuitBatchRequest();
$intuitBatchRequest->BatchItemRequest = $this->batchRequests;
$uri = "company/{1}/batch?requestid=" . $requestID;
$uri = str_replace('{1}', $this->serviceContext->realmId, $uri);
// Creates request parameters
$requestParameters = new RequestParameters($uri, 'POST', CoreConstants::CONTENTTYPE_APPLICATIONXML, null);
$restRequestHandler = $this->getRestHandler();
try {
// Get literal XML representation of IntuitBatchRequest into a DOMDocument
$httpsPostBodyPreProcessed = XmlObjectSerializer::getPostXmlFromArbitraryEntity($intuitBatchRequest, $urlResource);
$doc = new \DOMDocument();
$domObj = $doc->loadXML($httpsPostBodyPreProcessed);
$xpath = new \DOMXPath($doc);
// Replace generically-named IntuitObject nodes with tags that describe contained objects
$objectIndex = 0;
while (1) {
$matchingElementArray = $xpath->query("//IntuitObject");
if (is_null($matchingElementArray)) {
break;
}
if ($objectIndex>=count($intuitBatchRequest->BatchItemRequest)) {
break;
}
foreach ($matchingElementArray as $oneNode) {
// Found a DOMNode currently named "IntuitObject". Need to rename to
// entity that describes it's contents, like "ns0:Customer" (determine correct
// name by inspecting IntuitObject's class).
if ($intuitBatchRequest->BatchItemRequest[$objectIndex]->IntuitObject) {
// Determine entity name to use
$entityClassName = get_class($intuitBatchRequest->BatchItemRequest[$objectIndex]->IntuitObject);
$entityTransferName = XmlObjectSerializer::cleanPhpClassNameToIntuitEntityName($entityClassName);
$entityTransferName = 'ns0:'.$entityTransferName;
// Replace old-named DOMNode with new-named DOMNode
$newNode = $oneNode->ownerDocument->createElement($entityTransferName);
if ($oneNode->attributes->length) {
foreach ($oneNode->attributes as $attribute) {
$newNode->setAttribute($attribute->nodeName, $attribute->nodeValue);
}
}
while ($oneNode->firstChild) {
$newNode->appendChild($oneNode->firstChild);
}
$oneNode->parentNode->replaceChild($newNode, $oneNode);
}
break;
}
$objectIndex++;
}
$httpsPostBody = $doc->saveXML();
list($responseCode, $responseBody) = $restRequestHandler->sendRequest($requestParameters, $httpsPostBody, null, $this->isThrowExceptionOnError);
$faultHandler = $restRequestHandler->getFaultHandler();
if ($faultHandler) {
$this->lastError = $faultHandler;
return null;
}else{
$this->lastError = false;
}
} catch (\Exception $e) {
IdsExceptionManager::HandleException($e);
}
try {
// No JSON support here yet
// de serialize object
$responseXmlObj = simplexml_load_string($responseBody);
foreach ($responseXmlObj as $oneXmlObj) {
// process batch item
$intuitBatchItemResponse = $this->ProcessBatchItemResponse($oneXmlObj);
$this->intuitBatchItemResponses[$intuitBatchItemResponse->batchItemId] = $intuitBatchItemResponse;
}
} catch (\Exception $e) {
$this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Encountered an error parsing the batch response." . $e->getMessage());
$this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Error, "Stack Trace: " . $e->getTraceAsString());
return null;
}
$this->serviceContext->IppConfiguration->Logger->CustomLogger->Log(TraceLevel::Info, "Finished Execute method for batch.");
}
/**
* Returns handler to communicate with service
* @return RestHandler
*/
protected function getRestHandler()
{
return $this->restHandler;
}
private function verifyFault($fault)
{
if ($fault == null) {
return null;
}
if (empty($fault)) {
return null;
}
if (!$fault instanceof \SimpleXMLElement) {
return null;
}
if (!$fault->attributes() instanceof \SimpleXMLElement) {
return null;
}
if (!isset($fault->attributes()->type)) {
return null;
}
return true;
}
private function collectErrors($fault)
{
$errors = array();
if (isset($fault->Error)
&& ($fault->Error instanceof \SimpleXMLElement)
&& $fault->Error->count()) {
foreach ($fault->Error as $item) {
if (!isset($item->Message)) {
continue;
}
if (!$item->Message instanceof \SimpleXMLElement) {
continue;
}
$error = new \stdClass();
$detail = (string)$item->Detail;
if($detail) {
$error->message = (string)$item->Message . ' - ' . $detail;
} else {
$error->message = (string)$item->Message;
}
$error->code = null;
if ($item->attributes() instanceof \SimpleXMLElement
&& isset($item->attributes()->code)) {
$error->code = (string)$item->attributes()->code;
}
$errors[] =$error;
}
}
return $errors;
}
/**
* Helper function for store the error message and code from Fault returned from QuickBooks Online
*/
private function arrayToMessageAndCode(array $array)
{
if (empty($array)) {
return array(null,null);
}
if (1 == count($array)) {
$item = array_pop($array);
return array($item->message,$item->code);
}
$message = "";
$code = "";
foreach ($array as $item) {
$message .= "Exception: ".$item->message . "\n";
if (empty($code) && !empty($item->code)) {
$code = $item->code;
}
}
return array($message,$code);
}
/**
* Prepare IdsException out of Fault object.
* @param Fault fault Fault object.
* @return IdsException IdsException object.
*/
public function IterateFaultAndPrepareException($fault)
{
if (!$this->verifyFault($fault)) {
return null;
}
// Collect information from XML entity
$type = (string)$fault->attributes()->type;
list($message, $code) = $this->arrayToMessageAndCode($this->collectErrors($fault));
if (is_null($message)) {
return new IdsException("Fault Exception of type: " . $type . " has been generated.");
}
$idsException = null;
// Fault types can be of Validation, Service, Authentication and Authorization. Run them through the switch case.
switch ($type) {
// If Validation errors iterate the Errors and add them to the list of exceptions.
case "Validation":
case "ValidationFault":
// Throw specific exception like ValidationException.
$idsException = new ValidationException($message, $code);
break;
// If Validation errors iterate the Errors and add them to the list of exceptions.
case "Service":
case "ServiceFault":
// Throw specific exception like ServiceException.
$idsException = new ServiceException($message, $code);
break;
// If Validation errors iterate the Errors and add them to the list of exceptions.
case "Authentication":
case "AuthenticationFault":
case "Authorization":
case "AuthorizationFault":
$idsException = new SecurityException($message, $code);
break;
// Use this as default if there was some other type of Fault
default:
$idsException = new IdsException($message, $code);
}
// Return idsException which will be of type Validation, Service or Security.
return $idsException;
}
/**
* process batch item response
* @param BatchItemResponse oneXmlObj The batchitem response.
* @return IntuitBatchResponse IntuitBatchResponse object.
*/
private function ProcessBatchItemResponse($oneXmlObj)
{
$result = new IntuitBatchResponse();
if (null==$oneXmlObj) {
return $result;
}
if(isset($oneXmlObj["bId"])){
$bid = (String)$oneXmlObj["bId"];
$result->batchItemId = $bid;
}else{
throw new \Exception("No bid Found on the Batch Response.");
}
$firstChild = null;
foreach ($oneXmlObj->children() as $oneChild) {
$firstChild = $oneChild;
break;
}
if (!$firstChild) {
return $result;
}
$firstChildName = (string)$firstChild->getName();
switch ($firstChildName) {
//For batch query result
case "QueryResponse":
$result->responseType = UtilityConstants::Query;
$queryResult = array();
foreach ($oneXmlObj->QueryResponse->children() as $oneResponse) {
$oneEntity = $this->responseSerializer->Deserialize('<RestResponse>'.$oneResponse->asXML().'</RestResponse>');
$queryResult = array_merge($queryResult, $oneEntity);
}
$result->setEntities($queryResult);
$result->successFlagOn();
break;
//For batch failure result
case "Fault":
$result->responseType = UtilityConstants::Exception;
$idsException = $this->IterateFaultAndPrepareException($firstChild);
if($this->debugMode) {
$interface = $this->restHandler->getHttpClientInterface();
$responseInterface = $interface->getLastResponse();
$debugInfo = [
'intuit_tid' => $responseInterface->getIntuitTid(),
'body' => $responseInterface->getBody(),
'headers' => $responseInterface->getHeaders(),
];
$idsException->setDebug($debugInfo);
}
$result->exception = $idsException;
break;
//For batch Entity Result
default:
$result->responseType = UtilityConstants::Entity;
$oneEntityArray = $this->responseSerializer->Deserialize('<RestResponse>'.$firstChild->asXML().'</RestResponse>');
$oneEntity = $oneEntityArray[0];
$result->entity = $oneEntity;
$result->successFlagOn();
break;
}
return $result;
}
}