3namespace Bitrix\Sale\Cashbox;
6use Bitrix\Main\Localization;
7use Bitrix\Main\PhoneNumber;
21 private const PARTNER_CODE_BITRIX =
'3010144';
32 private $pathToSslCertificate =
'';
33 private $pathToSslCertificateKey =
'';
41 private const MAX_TEXT_LENGTH = 128;
55 private function getCheckTypeMap()
81 private function getCalculatedSignMap()
97 ($check->
getType() ===
'sellreturn')
117 $calculatedSignMap = $this->getCalculatedSignMap();
120 'id' => static::buildUuid(static::UUID_TYPE_CHECK, $checkData[
'unique_id']),
122 'group' => $this->
getField(
'NUMBER_KKM') ?:
null,
125 'type' => $calculatedSignMap[$checkData[
'calculated_sign']],
131 'customerContact' => $this->getCustomerContact($checkData),
132 'isInternetStore' => $this->
getField(
'USE_OFFLINE') ===
'N',
134 'meta' => self::PARTNER_CODE_BITRIX
137 foreach ($checkData[
'items'] as $item)
142 $paymentTypeMap = $this->getPaymentTypeMap();
143 foreach ($checkData[
'payments'] as
$payment)
145 $result[
'content'][
'checkClose'][
'payments'][] = [
146 'type' => $paymentTypeMap[
$payment[
'type']],
171 if (isset($item[
'nomenclature_code']))
173 $result[
'nomenclatureCode'] = $this->buildPositionNomenclatureCode($item);
176 if (isset($item[
'supplier_info']))
191 return mb_substr($item[
'name'], 0, self::MAX_TEXT_LENGTH);
200 return $item[
'quantity'];
209 return $item[
'price'];
218 $checkType = $this->getCheckTypeMap();
220 return $checkType[$checkData[
'type']];
231 return $paymentObjectMap[$item[
'payment_object']];
247 return $this->mapVatValue($checkData[
'type'],
$vat);
254 private function buildPositionNomenclatureCode(
array $item)
256 return base64_encode($item[
'nomenclature_code']);
272 'supplierInfo' =>
null,
273 'supplierINN' =>
null,
280 if (!empty($supplier[
'phones']))
284 foreach ($supplier[
'phones'] as $phone)
286 $phoneNumber = $phoneParser->parse($phone);
290 $phoneLength += mb_strlen($formattedPhone) + 4;
291 if ($phoneLength > $maxTagLength)
296 $result[
'supplierInfo'][
'phoneNumbers'][] = $formattedPhone;
301 if (!empty($supplier[
'name']) && $phoneLength < $maxTagLength)
303 $result[
'supplierInfo'][
'name'] = mb_substr($supplier[
'name'], 0, $maxTagLength - $phoneLength);
306 if (!empty($supplier[
'supplier_info'][
'inn']))
308 $result[
'supplierINN'] = $supplier[
'supplier_info'][
'inn'];
319 private function mapVatValue($checkType,
$vat)
325 $map = $mapper->getMap();
333 self::CODE_VAT_10 => self::CODE_CALC_VAT_10,
334 self::CODE_VAT_20 => self::CODE_CALC_VAT_20,
342 private function getCustomerContact(
array $data)
346 if ($customerContact ===
'EMAIL')
348 return $data[
'client_email'];
350 elseif ($customerContact ===
'PHONE')
353 if ($phone[0] !==
'7')
361 if (
$data[
'client_phone'])
364 if ($phone[0] !==
'7')
372 return $data[
'client_email'];
416 private function getPaymentTypeMap()
431 private function getPostQueryHeaders(
$url,
$data)
441 $header =
"POST ".$urlObj->getPath().
" HTTP/1.0\r\n";
442 $header .=
"Host: ".$urlObj->getHost().
"\r\n";
443 $header .=
"Accept: application/json\r\n";
444 $header .=
"Content-Type: application/json\r\n";
445 $header .=
"X-Signature: ".$sign.
"\r\n";
446 $header .= sprintf(
"Content-length: %s\r\n", strlen(
$data));
470 $this->getUrl().
'/documents/',
486 $encodedData = $this->encode(
$data);
488 $headers = $this->getPostQueryHeaders(
$url, $encodedData);
489 if ($headers ===
false)
493 Localization\Loc::getMessage(
'SALE_CASHBOX_ORANGE_DATA_ERROR_SIGN')
498 $queryResult = $this->send(
$url, $headers, $encodedData);
499 if (!$queryResult->isSuccess())
501 return $result->addErrors($queryResult->getErrors());
512 private function getUrl()
516 return static::HANDLER_ACTIVE_URL;
519 return static::HANDLER_TEST_URL;
529 private function send(
$url, $headers,
$data =
'')
531 $context = $this->createStreamContext();
535 $client = stream_socket_client(
$url, $errNumber, $errString, 5, STREAM_CLIENT_CONNECT,
$context);
538 if ($client !==
false)
542 fputs($client, $headers.$data);
543 $response = stream_get_contents($client);
549 $httpCode = $this->extractResponseStatus($responseHeaders);
554 $httpCode !== static::RESPONSE_HTTP_CODE_201
556 $httpCode !== static::RESPONSE_HTTP_CODE_200
566 $error = Localization\Loc::getMessage(
'SALE_CASHBOX_ORANGE_DATA_ERROR_RESPONSE_'.$httpCode);
569 $error = Localization\Loc::getMessage(
'SALE_CASHBOX_ORANGE_DATA_ERROR_CHECK_PRINT');
580 Localization\Loc::getMessage(
'SALE_CASHBOX_ORANGE_DATA_ERROR_SEND_QUERY')
584 $error =
new Errors\Error($errNumber.
': '.$errString);
595 private function extractResponseStatus($headers)
597 $headers = explode(
"\n", $headers);
598 preg_match(
'#HTTP\S+ (\d+)#', $headers[0], $find);
600 return (
int)$find[1];
608 if ($this->pathToSslCertificate !==
''
609 &&
Main\
IO\File::isFileExists($this->pathToSslCertificate)
612 unlink($this->pathToSslCertificate);
615 if ($this->pathToSslCertificateKey !==
''
616 &&
Main\
IO\File::isFileExists($this->pathToSslCertificateKey)
619 unlink($this->pathToSslCertificateKey);
626 private function createStreamContext()
629 $this->pathToSslCertificate = $this->createTmpFile($sslCert);
632 $this->pathToSslCertificateKey = $this->createTmpFile($sslKey);
634 return stream_context_create([
636 'local_cert' => $this->pathToSslCertificate,
637 'local_pk' => $this->pathToSslCertificateKey,
650 $url = $this->getUrl();
651 $url .=
'/documents/'.$this->getValueFromSettings(
'SERVICE',
'INN').
'/status/'.$check->
getField(
'EXTERNAL_UUID');
665 $header = $this->getCheckQueryHeaders(
$url);
666 $queryResult = $this->send(
$url, $header);
668 if (!$queryResult->isSuccess())
670 return $result->addErrors($queryResult->getErrors());
673 $data = $queryResult->getData();
681 return static::applyCheckResult(
$response);
704 'group' => $this->
getField(
'NUMBER_KKM') ?:
null,
716 $url = $this->getUrl().
'/check/';
718 $encodedData = $this->encode(
$data);
720 $headers = $this->getPostQueryHeaders(
$url, $encodedData);
722 return $this->send(
$url, $headers, $encodedData);
729 private function getCheckQueryHeaders(
$url)
733 $header =
"GET ".$urlObj->getPath().
" HTTP/1.0\r\n";
734 $header .=
"Host: ".$urlObj->getHost().
"\r\n";
735 $header .=
"Accept: application/json\r\n";
736 $header .=
"Content-Type: application/json\r\n";
759 if (empty($checkInfo))
764 $result[
'ID'] = $checkInfo[
'ID'];
765 $result[
'CHECK_TYPE'] = $checkInfo[
'TYPE'];
790 if (!function_exists(
'openssl_get_privatekey') || !function_exists(
'openssl_private_encrypt'))
795 $data = pack(
'H*',
'3031300d060960864801650304020105000420') . hash(
'sha256',
$data,
true);
802 openssl_private_encrypt(
$data,
$res, $pk);
803 return base64_encode(
$res);
820 private function decode(
$data)
826 catch (
Main\ArgumentException $exception)
836 private function createTmpFile(
$data)
838 $filePath = tempnam(sys_get_temp_dir(),
'orange_data');
839 if ($filePath ===
false)
846 file_put_contents($filePath,
$data);
867 'TYPE' =>
'DATABASE_FILE',
868 'CLASS' =>
'adm-designed-file',
874 'TYPE' =>
'DATABASE_FILE',
875 'CLASS' =>
'adm-designed-file',
881 'TYPE' =>
'DATABASE_FILE',
882 'CLASS' =>
'adm-designed-file',
938 if (
Main\Loader::includeModule(
'catalog'))
944 $defaultVatList = static::getDefaultVatList();
949 if (isset($defaultVatList[(
int)
$vat[
'RATE']]))
950 $value = $defaultVatList[(int)
$vat[
'RATE']];
954 'LABEL' =>
$vat[
'NAME'].
' ['.(
int)
$vat[
'RATE'].
'%]',
981 if (static::hasMeasureSettings())
983 $settings[
'MEASURE'] = static::getMeasureSettings();
1006 0 => self::CODE_VAT_0,
1007 10 => self::CODE_VAT_10,
1008 20 => self::CODE_VAT_20,
1032 if (
Main\Loader::includeModule(
'catalog'))
1034 $measuresList = \CCatalogMeasure::getList();
1035 while ($measure = $measuresList->fetch())
1037 $measureItems[$measure[
'CODE']] = [
1039 'LABEL' => $measure[
'MEASURE_TITLE'],
1047 'ITEMS' => $measureItems,
1062 foreach (static::getSettings()[
'SECURITY'][
'ITEMS'] as $fieldId => $field)
1064 $error =
$files[
'error'][
'SECURITY'][$fieldId] ??
null;
1065 $tmpName =
$files[
'tmp_name'][
'SECURITY'][$fieldId] ??
null;
1067 if ($field[
'TYPE'] ===
'DATABASE_FILE'
1107 return '/corrections/';
1119 $calculatedSignMap = $this->getCalculatedSignMap();
1122 'id' => static::buildUuid(static::UUID_TYPE_CHECK,
$data[
'unique_id']),
1124 'group' => $this->
getField(
'NUMBER_KKM') ?:
null,
1127 'type' => $calculatedSignMap[
$data[
'calculated_sign']],
1136 foreach ($data[
'payments'] as
$payment)
1149 if (is_array($vats))
1151 foreach ($vats as
$vat)
1168 return $documentDate->format(
'Y-m-d\TH:i:s');
1177 return $correctionInfo[
'document_number'];
1186 return $correctionInfo[
'total_sum'];
1195 if (!isset(
$data[
'vats']) || !is_array(
$data[
'vats']) || empty(
$data[
'vats']))
1201 foreach (
$data[
'vats'] as $item)
1211 case self::CODE_VAT_0:
1214 case self::CODE_VAT_10:
1217 case self::CODE_VAT_20:
1227 'value' => $item[
'sum']
1268 . $check->
getField(
'EXTERNAL_UUID')
if(!Loader::includeModule('catalog')) if(!AccessController::getCurrent() ->check(ActionDictionary::ACTION_PRICE_EDIT)) if(!check_bitrix_sessid()) $request
static loadMessages($file)
static getMessage($code, $replace=null, $language=null)
static getList(array $parameters=array())
static encode($data, $options=null)
const CALCULATED_SIGN_INCOME
const PARAM_CALCULATION_ATTR
const PAYMENT_TYPE_ADVANCE
const PAYMENT_TYPE_CREDIT
const PARAM_FISCAL_DOC_ATTR
const PARAM_FISCAL_DOC_NUMBER
const CALCULATED_SIGN_CONSUMPTION
const PARAM_FISCAL_RECEIPT_NUMBER
const PARAM_REG_NUMBER_KKT
const PAYMENT_TYPE_CASHLESS
getValueFromSettings($name, $code)
buildPositionQuantity(array $item)
static extractSettingsFromRequest(Main\HttpRequest $request)
getCorrectionTypeMap($type)
buildPositionPrice(array $item)
const RESPONSE_HTTP_CODE_200
static getSettings($modelId=0)
buildPositionPaymentMethodType(array $checkData)
printCorrectionImmediately(CorrectionCheck $check)
buildCorrectionCheckQuery(CorrectionCheck $check)
static getDefaultVatList()
static getMeasureSettings()
buildCheckQuery(Check $check)
getCheckData(AbstractCheck $check)
const RESPONSE_HTTP_CODE_201
buildCheckQueryByCheckData(array $checkData, bool $isSellReturn)
buildPositionPaymentSubjectType(array $item)
const HANDLER_MODE_ACTIVE
buildPositionText(array $item)
static extractCheckData(array $data)
buildPositionSupplier(array $supplier)
static hasMeasureSettings()
checkCorrection(CorrectionCheck $check)
printImmediately(Check $check)
getCorrectionTotalSum($correctionInfo)
getCorrectionCauseDocumentNumber($correctionInfo)
getVatsByCheckData(array $data)
getCorrectionCauseDocumentDate($correctionInfo)
registerCheck($url, $data)
buildPosition(array $checkData, array $item, bool $isSellReturn)
buildPositionTax(array $checkData, $item)
const PAYMENT_OBJECT_EXCISE
const PAYMENT_OBJECT_LOTTERY
const PAYMENT_OBJECT_SOCIAL_INSURANCE
const PAYMENT_OBJECT_COMPOSITE
const PAYMENT_OBJECT_LOTTERY_PRIZE
const PAYMENT_OBJECT_MEDICAL_INSURANCE_IP
const PAYMENT_OBJECT_COMMODITY_MARKING_EXCISE
const PAYMENT_OBJECT_NON_OPERATING_GAIN
const PAYMENT_OBJECT_COMMODITY_MARKING_NO_MARKING_EXCISE
const PAYMENT_OBJECT_RESORT_FEE
const PAYMENT_OBJECT_PENSION_INSURANCE_IP
const PAYMENT_OBJECT_PROPERTY_RIGHT
const PAYMENT_OBJECT_GAMBLING_PRIZE
const PAYMENT_OBJECT_COMMODITY_MARKING
const PAYMENT_OBJECT_COMMODITY
const PAYMENT_OBJECT_AGENT_COMMISSION
const PAYMENT_OBJECT_ANOTHER
const PAYMENT_OBJECT_DEPOSIT
const PAYMENT_OBJECT_MEDICAL_INSURANCE
const PAYMENT_OBJECT_SERVICE
const PAYMENT_OBJECT_INTELLECTUAL_ACTIVITY
const PAYMENT_OBJECT_PAYMENT
const PAYMENT_OBJECT_EXPENSE
const PAYMENT_OBJECT_GAMBLING_BET
const PAYMENT_OBJECT_CASINO_PAYMENT
const PAYMENT_OBJECT_PENSION_INSURANCE
const PAYMENT_OBJECT_COMMODITY_MARKING_NO_MARKING
const PAYMENT_OBJECT_SALES_TAX
static getCheckInfoByExternalUuid($uuid)
static getObjectById($id)
const CORRECTION_TYPE_INSTRUCTION
const CORRECTION_TYPE_SELF
static addDebugInfo(?string $message, $cashboxId=null)
static addError(?string $message, $cashboxId=null)
static getTag2108Value(?string $measureCode)
</td ></tr ></table ></td ></tr >< tr >< td class="bx-popup-label bx-width30"><?=GetMessage("PAGE_NEW_TAGS")?> array( $site)
NormalizePhone($number, $minLength=10)
if( $daysToExpire >=0 &&$daysToExpire< 60 elseif)( $daysToExpire< 0)