| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* ZohoCrm Record Api |
| 5 |
* |
| 6 |
*/ |
| 7 |
|
| 8 |
namespace BitCode\BitForm\Core\Integration\ZohoCRM; |
| 9 |
|
| 10 |
use BitCode\BitForm\Core\Util\ApiResponse as UtilApiResponse; |
| 11 |
use BitCode\BitForm\Core\Util\DateTimeHelper; |
| 12 |
use BitCode\BitForm\Core\Util\HttpHelper; |
| 13 |
use WP_Error; |
| 14 |
|
| 15 |
/** |
| 16 |
* Provide functionality for Record insert,upsert |
| 17 |
*/ |
| 18 |
class RecordApiHelper |
| 19 |
{ |
| 20 |
protected $_defaultHeader; |
| 21 |
protected $_apiDomain; |
| 22 |
protected $_tokenDetails; |
| 23 |
protected $_logResponse; |
| 24 |
|
| 25 |
public function __construct($tokenDetails) |
| 26 |
{ |
| 27 |
$this->_defaultHeader['Authorization'] = "Zoho-oauthtoken {$tokenDetails->access_token}"; |
| 28 |
$this->_apiDomain = \urldecode($tokenDetails->api_domain); |
| 29 |
$this->_tokenDetails = $tokenDetails; |
| 30 |
$this->_logResponse = new UtilApiResponse(); |
| 31 |
} |
| 32 |
|
| 33 |
public function serachRecord($module, $searchCriteria) |
| 34 |
{ |
| 35 |
$searchRecordEndpoint = "{$this->_apiDomain}/crm/v2/{$module}/search"; |
| 36 |
return HttpHelper::get($searchRecordEndpoint, ['criteria' => "({$searchCriteria})"], $this->_defaultHeader); |
| 37 |
} |
| 38 |
|
| 39 |
public function upsertRecord($module, $data) |
| 40 |
{ |
| 41 |
$insertRecordEndpoint = "{$this->_apiDomain}/crm/v2/{$module}/upsert"; |
| 42 |
$data = \is_string($data) ? $data : wp_json_encode($data); |
| 43 |
return HttpHelper::post($insertRecordEndpoint, $data, $this->_defaultHeader); |
| 44 |
} |
| 45 |
|
| 46 |
public function insertRecord($module, $data) |
| 47 |
{ |
| 48 |
$insertRecordEndpoint = "{$this->_apiDomain}/crm/v2/{$module}"; |
| 49 |
$data = \is_string($data) ? $data : wp_json_encode($data); |
| 50 |
return HttpHelper::post($insertRecordEndpoint, $data, $this->_defaultHeader); |
| 51 |
} |
| 52 |
|
| 53 |
public function executeRecordApi($formID, $entryID, $integId, $logID, $defaultConf, $module, $layout, $fieldValues, $fieldMap, $actions, $required, $fileMap = [], $isRelated = false) |
| 54 |
{ |
| 55 |
$fieldData = []; |
| 56 |
$filesApiHelper = new FilesApiHelper($this->_tokenDetails, $formID, $entryID, $integId, $logID); |
| 57 |
foreach ($fieldMap as $fieldKey => $fieldPair) { |
| 58 |
if (!empty($fieldPair->zohoFormField)) { |
| 59 |
if (empty($defaultConf->layouts->{$module}->{$layout}->fields->{$fieldPair->zohoFormField})) { |
| 60 |
continue; |
| 61 |
} |
| 62 |
if ('custom' === $fieldPair->formField && isset($fieldPair->customValue)) { |
| 63 |
$fieldData[$fieldPair->zohoFormField] = $this->formatFieldValue($fieldPair->customValue, $defaultConf->layouts->{$module}->{$layout}->fields->{$fieldPair->zohoFormField}); |
| 64 |
} else { |
| 65 |
$fieldData[$fieldPair->zohoFormField] = $this->formatFieldValue($fieldValues[$fieldPair->formField], $defaultConf->layouts->{$module}->{$layout}->fields->{$fieldPair->zohoFormField}); |
| 66 |
} |
| 67 |
if (empty($fieldData[$fieldPair->zohoFormField]) && \in_array($fieldPair->zohoFormField, $required)) { |
| 68 |
$error = new WP_Error('REQ_FIELD_EMPTY', wp_sprintf(__('%s is required for zoho crm, %s module', 'bit-form'), $fieldPair->zohoFormField, $module)); |
| 69 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'record', 'type_name' => 'field'], 'validation', $error); |
| 70 |
return $error; |
| 71 |
} |
| 72 |
|
| 73 |
if (!empty($fieldData[$fieldPair->zohoFormField])) { |
| 74 |
$requiredLength = $defaultConf->layouts->{$module}->{$layout}->fields->{$fieldPair->zohoFormField}->length; |
| 75 |
$currentLength = is_array($fieldData[$fieldPair->zohoFormField]) || is_object($fieldData[$fieldPair->zohoFormField]) ? |
| 76 |
@count($fieldData[$fieldPair->zohoFormField]) |
| 77 |
: strlen($fieldData[$fieldPair->zohoFormField]); |
| 78 |
if ($currentLength > $requiredLength) { |
| 79 |
$error = new WP_Error('REQ_FIELD_LENGTH_EXCEEDED', wp_sprintf(__('zoho crm field %s\'s maximum length is %s, Given %s', 'bit-form'), $fieldPair->zohoFormField, $module)); |
| 80 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'record', 'type_name' => 'field'], 'validation', $error); |
| 81 |
return $error; |
| 82 |
} |
| 83 |
} |
| 84 |
} |
| 85 |
} |
| 86 |
|
| 87 |
if (count($fileMap)) { |
| 88 |
foreach ($fileMap as $fileKey => $filePair) { |
| 89 |
if (!empty($filePair->zohoFormField)) { |
| 90 |
if ('fileupload' === $defaultConf->layouts->{$module}->{$layout}->fileUploadFields->{$filePair->zohoFormField}->data_type && !empty($fieldValues[$filePair->formField])) { |
| 91 |
$files = $fieldValues[$filePair->formField]; |
| 92 |
$fileLength = $defaultConf->layouts->{$module}->{$layout}->fileUploadFields->{$filePair->zohoFormField}->length; |
| 93 |
if (\is_array($files) && count($files) !== $fileLength) { |
| 94 |
$files = array_slice($fieldValues[$filePair->formField], 0, $fileLength); |
| 95 |
} |
| 96 |
$uploadsIDs = $filesApiHelper->uploadFiles($files); |
| 97 |
if ($uploadsIDs) { |
| 98 |
$fieldData[$filePair->zohoFormField] = $uploadsIDs; |
| 99 |
} |
| 100 |
} |
| 101 |
} |
| 102 |
} |
| 103 |
} |
| 104 |
if (!empty($defaultConf->layouts->{$module}->{$layout}->id)) { |
| 105 |
$fieldData['Layout']['id'] = $defaultConf->layouts->{$module}->{$layout}->id; |
| 106 |
} |
| 107 |
if (!empty($actions->gclid) && isset($fieldValues['GCLID'])) { |
| 108 |
$fieldData['$gclid'] = $fieldValues['GCLID']; |
| 109 |
} |
| 110 |
if (!empty($actions->rec_owner)) { |
| 111 |
$fieldData['Owner']['id'] = $actions->rec_owner; |
| 112 |
} |
| 113 |
$requestParams['data'][] = (object) $fieldData; |
| 114 |
$requestParams['trigger'] = []; |
| 115 |
if (!empty($actions->workflow)) { |
| 116 |
$requestParams['trigger'][] = 'workflow'; |
| 117 |
} |
| 118 |
if (!empty($actions->approval)) { |
| 119 |
$requestParams['trigger'][] = 'approval'; |
| 120 |
} |
| 121 |
if (!empty($actions->blueprint)) { |
| 122 |
$requestParams['trigger'][] = 'blueprint'; |
| 123 |
} |
| 124 |
if (!empty($actions->assignment_rules)) { |
| 125 |
$requestParams['lar_id'] = $actions->assignment_rules; |
| 126 |
} |
| 127 |
$recordApiResponse = ''; |
| 128 |
if (!empty($actions->upsert) && !empty($actions->upsert->crmField)) { |
| 129 |
$requestParams['duplicate_check_fields'] = []; |
| 130 |
if (!empty($actions->upsert)) { |
| 131 |
$duplicateCheckFields = []; |
| 132 |
$searchCriteria = ''; |
| 133 |
foreach ($actions->upsert->crmField as $fieldInfo) { |
| 134 |
if (!empty($fieldInfo->name) && $fieldData[$fieldInfo->name]) { |
| 135 |
$duplicateCheckFields[] = $fieldInfo->name; |
| 136 |
if (empty($searchCriteria)) { |
| 137 |
$searchCriteria .= "({$fieldInfo->name}:equals:{$fieldData[$fieldInfo->name]})"; |
| 138 |
} else { |
| 139 |
$searchCriteria .= "and({$fieldInfo->name}:equals:{$fieldData[$fieldInfo->name]})"; |
| 140 |
} |
| 141 |
} |
| 142 |
} |
| 143 |
if (isset($actions->upsert->overwrite) && !$actions->upsert->overwrite && !empty($searchCriteria)) { |
| 144 |
$searchRecordApiResponse = $this->serachRecord($module, $searchCriteria); |
| 145 |
if (!empty($searchRecordApiResponse) && !empty($searchRecordApiResponse->data)) { |
| 146 |
$previousData = $searchRecordApiResponse->data[0]; |
| 147 |
foreach ($fieldData as $apiName => $currentValue) { |
| 148 |
if (!empty($previousData->{$apiName})) { |
| 149 |
$fieldData[$apiName] = $previousData->{$apiName}; |
| 150 |
} |
| 151 |
} |
| 152 |
$requestParams['data'][] = (object) $fieldData; |
| 153 |
} |
| 154 |
} |
| 155 |
$requestParams['duplicate_check_fields'] = $duplicateCheckFields; |
| 156 |
} |
| 157 |
$recordApiResponse = $this->upsertRecord($module, (object) $requestParams); |
| 158 |
} elseif ($isRelated) { |
| 159 |
$recordApiResponse = $this->insertRecord($module, (object) $requestParams); |
| 160 |
} else { |
| 161 |
$recordApiResponse = $this->upsertRecord($module, (object) $requestParams); |
| 162 |
} |
| 163 |
if (isset($recordApiResponse->status) && 'error' === $recordApiResponse->status) { |
| 164 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'record', 'type_name' => $module], 'error', $recordApiResponse); |
| 165 |
} else { |
| 166 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'record', 'type_name' => $module], 'success', $recordApiResponse); |
| 167 |
} |
| 168 |
if ( |
| 169 |
!empty($recordApiResponse->data) |
| 170 |
&& !empty($recordApiResponse->data[0]->code) |
| 171 |
&& 'SUCCESS' === $recordApiResponse->data[0]->code |
| 172 |
&& !empty($recordApiResponse->data[0]->details->id) |
| 173 |
) { |
| 174 |
if (!empty($actions->tag_rec)) { |
| 175 |
$tags = ''; |
| 176 |
$tag_rec = \explode(',', $actions->tag_rec); |
| 177 |
foreach ($tag_rec as $tag) { |
| 178 |
if (is_string($tag) && '${' === substr($tag, 0, 2) && '}' === $tag[strlen($tag) - 1]) { |
| 179 |
$tags .= (!empty($tags) ? ',' : '') . $fieldValues[substr($tag, 2, strlen($tag) - 3)]; |
| 180 |
} else { |
| 181 |
$tags .= (!empty($tags) ? ',' : '') . $tag; |
| 182 |
} |
| 183 |
} |
| 184 |
$tagApiHelper = new TagApiHelper($this->_tokenDetails, $module); |
| 185 |
$addTagResponse = $tagApiHelper->addTagsSingleRecord($recordApiResponse->data[0]->details->id, $tags); |
| 186 |
if (isset($addTagResponse->status) && 'error' === $addTagResponse->status) { |
| 187 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'tag', 'type_name' => $module], 'error', $addTagResponse); |
| 188 |
} else { |
| 189 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'tag', 'type_name' => $module], 'success', $addTagResponse); |
| 190 |
} |
| 191 |
} |
| 192 |
if (!empty($actions->attachment)) { |
| 193 |
$validAttachments = []; |
| 194 |
$fileFound = 0; |
| 195 |
$responseType = 'success'; |
| 196 |
$attachmentApiResponses = []; |
| 197 |
$attachment = explode(',', $actions->attachment); |
| 198 |
foreach ($attachment as $fileField) { |
| 199 |
if (isset($fieldValues[$fileField]) && !empty($fieldValues[$fileField])) { |
| 200 |
$fileFound = 1; |
| 201 |
if (is_array($fieldValues[$fileField])) { |
| 202 |
foreach ($fieldValues[$fileField] as $singleFile) { |
| 203 |
$attachmentApiResponse = $filesApiHelper->uploadFiles($singleFile, true, $module, $recordApiResponse->data[0]->details->id); |
| 204 |
if (isset($attachmentApiResponse->status) && 'error' === $attachmentApiResponse->status) { |
| 205 |
$responseType = 'error'; |
| 206 |
} |
| 207 |
} |
| 208 |
} else { |
| 209 |
$attachmentApiResponse = $filesApiHelper->uploadFiles($fieldValues[$fileField], true, $module, $recordApiResponse->data[0]->details->id); |
| 210 |
if (isset($attachmentApiResponse->status) && 'error' === $attachmentApiResponse->status) { |
| 211 |
$responseType = 'error'; |
| 212 |
} |
| 213 |
} |
| 214 |
} |
| 215 |
} |
| 216 |
if ($fileFound) { |
| 217 |
$this->_logResponse->apiResponse($logID, $integId, ['type' => 'attachment', 'type_name' => $module], $responseType, $attachmentApiResponses); |
| 218 |
} |
| 219 |
} |
| 220 |
} |
| 221 |
return $recordApiResponse; |
| 222 |
} |
| 223 |
|
| 224 |
public function formatFieldValue($value, $formatSpecs) |
| 225 |
{ |
| 226 |
if (empty($value)) { |
| 227 |
return ''; |
| 228 |
} |
| 229 |
|
| 230 |
switch ($formatSpecs->json_type) { |
| 231 |
case 'jsonarray': |
| 232 |
$apiFormat = 'array'; |
| 233 |
break; |
| 234 |
case 'jsonobject': |
| 235 |
$apiFormat = 'object'; |
| 236 |
break; |
| 237 |
|
| 238 |
default: |
| 239 |
$apiFormat = $formatSpecs->json_type; |
| 240 |
break; |
| 241 |
} |
| 242 |
|
| 243 |
$formatedValue = ''; |
| 244 |
$fieldFormat = gettype($value); |
| 245 |
if ($fieldFormat === $apiFormat && 'datetime' !== $formatSpecs->data_type) { |
| 246 |
$formatedValue = $value; |
| 247 |
} else { |
| 248 |
if ('array' === $apiFormat || 'object' === $apiFormat) { |
| 249 |
if ('string' === $fieldFormat) { |
| 250 |
if (-1 === strpos($value, ',')) { |
| 251 |
$formatedValue = json_decode($value); |
| 252 |
} else { |
| 253 |
$formatedValue = explode(',', $value); |
| 254 |
} |
| 255 |
$formatedValue = is_null($formatedValue) && !is_null($value) ? [$value] : $formatedValue; |
| 256 |
} else { |
| 257 |
$formatedValue = $value; |
| 258 |
} |
| 259 |
|
| 260 |
if ('object' === $apiFormat) { |
| 261 |
$formatedValue = (object) $formatedValue; |
| 262 |
} |
| 263 |
} elseif ('string' === $apiFormat && 'datetime' !== $formatSpecs->data_type) { |
| 264 |
$formatedValue = !is_string($value) ? wp_json_encode($value) : $value; |
| 265 |
} elseif ('datetime' === $formatSpecs->data_type) { |
| 266 |
$dateTimeHelper = new DateTimeHelper(); |
| 267 |
$formatedValue = $dateTimeHelper->getFormated($value, 'Y-m-d\TH:i', wp_timezone(), 'Y-m-d\TH:i:sP', null); |
| 268 |
} else { |
| 269 |
$stringyfiedValue = !is_string($value) ? wp_json_encode($value) : $value; |
| 270 |
|
| 271 |
switch ($apiFormat) { |
| 272 |
case 'double': |
| 273 |
$formatedValue = (float) $stringyfiedValue; |
| 274 |
break; |
| 275 |
|
| 276 |
case 'boolean': |
| 277 |
$formatedValue = (bool) $stringyfiedValue; |
| 278 |
break; |
| 279 |
|
| 280 |
case 'integer': |
| 281 |
$formatedValue = (int) $stringyfiedValue; |
| 282 |
break; |
| 283 |
|
| 284 |
default: |
| 285 |
$formatedValue = $stringyfiedValue; |
| 286 |
break; |
| 287 |
} |
| 288 |
} |
| 289 |
} |
| 290 |
$formatedValueLenght = 'array' === $apiFormat || 'object' === $apiFormat ? (is_countable($formatedValue) ? \count($formatedValue) : @count($formatedValue)) : \strlen($formatedValue); |
| 291 |
if ($formatedValueLenght > $formatSpecs->length) { |
| 292 |
$formatedValue = 'array' === $apiFormat || 'object' === $apiFormat ? array_slice($formatedValue, 0, $formatSpecs->length) : substr($formatedValue, 0, $formatSpecs->length); |
| 293 |
} |
| 294 |
|
| 295 |
return $formatedValue; |
| 296 |
} |
| 297 |
} |
| 298 |
|