%PDF- %PDF-
| Direktori : /proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/cashbox/ |
| Current File : //proc/self/root/home/bitrix/www/bitrix/modules/sale/lib/cashbox/cashboxatolfarm.php |
<?php
namespace Bitrix\Sale\Cashbox;
use Bitrix\Main;
use Bitrix\Main\Localization;
use Bitrix\Sale\Cashbox\Internals\CashboxTable;
use Bitrix\Sale\Result;
use Bitrix\Catalog;
Localization\Loc::loadMessages(__FILE__);
/**
* Class CashboxAtolFarm
* @package Bitrix\Sale\Cashbox
*/
class CashboxAtolFarm extends Cashbox implements IPrintImmediately, ICheckable
{
const OPERATION_CHECK_REGISTRY = 'registry';
const OPERATION_CHECK_CHECK = 'check';
const REQUEST_TYPE_GET = 'get';
const REQUEST_TYPE_POST = 'post';
const TOKEN_OPTION_NAME = 'atol_access_token';
const SERVICE_URL = 'https://online.atol.ru/possystem/v3';
const RESPONSE_HTTP_CODE_401 = 401;
const RESPONSE_HTTP_CODE_200 = 200;
/**
* @param Check $check
* @return array
*/
public function buildCheckQuery(Check $check)
{
$data = $check->getDataForCheck();
/** @var Main\Type\DateTime $dateTime */
$dateTime = $data['date_create'];
$result = array(
'timestamp' => $dateTime->format('d.m.Y H:i:s'),
'external_id' => static::buildUuid(static::UUID_TYPE_CHECK, $data['unique_id']),
'service' => array(
'inn' => $this->getValueFromSettings('SERVICE', 'INN'),
'callback_url' => $this->getCallbackUrl(),
'payment_address' => $this->getValueFromSettings('SERVICE', 'P_ADDRESS'),
),
'receipt' => array(
'attributes' => array(
'sno' => $this->getValueFromSettings('TAX', 'SNO')
),
'payments' => array(),
'items' => array(),
'total' => (float)$data['total_sum']
)
);
$phone = \NormalizePhone($data['client_phone']);
if (is_string($phone))
{
if ($phone[0] === '7')
$phone = substr($phone, 1);
}
else
{
$phone = '';
}
$email = $data['client_email'] ?: '';
$clientInfo = $this->getValueFromSettings('CLIENT', 'INFO');
if ($clientInfo === 'PHONE')
{
$result['receipt']['attributes'] = ['phone' => $phone];
}
elseif ($clientInfo === 'EMAIL')
{
$result['receipt']['attributes'] = ['email' => $email];
}
else
{
$result['receipt']['attributes'] = [
'email' => $email,
'phone' => $phone,
];
}
foreach ($data['payments'] as $payment)
{
$result['receipt']['payments'][] = array(
'type' => (int)$this->getValueFromSettings('PAYMENT_TYPE', $payment['type']),
'sum' => (float)$payment['sum']
);
}
foreach ($data['items'] as $i => $item)
{
$vat = $this->getValueFromSettings('VAT', $item['vat']);
$result['receipt']['items'][] = array(
'name' => $item['name'],
'price' => (float)$item['price'],
'sum' => (float)$item['sum'],
'quantity' => $item['quantity'],
'tax' => ($vat !== null) ? $vat : $this->getValueFromSettings('VAT', 'NOT_VAT')
);
}
return $result;
}
/**
* @return string
*/
protected function getCallbackUrl()
{
$context = Main\Application::getInstance()->getContext();
$scheme = $context->getRequest()->isHttps() ? 'https' : 'http';
$server = $context->getServer();
$domain = $server->getServerName();
if (preg_match('/^(?<domain>.+):(?<port>\d+)$/', $domain, $matches))
{
$domain = $matches['domain'];
$port = $matches['port'];
}
else
{
$port = $server->getServerPort();
}
$port = in_array($port, array(80, 443)) ? '' : ':'.$port;
return sprintf('%s://%s%s/bitrix/tools/sale_farm_check_print.php', $scheme, $domain, $port);
}
/**
* @return string
*/
public static function getName()
{
return Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_TITLE');
}
/**
* @param array $data
* @return array
*/
protected static function extractCheckData(array $data)
{
$result = array();
if (!$data['uuid'])
return $result;
$checkInfo = CheckManager::getCheckInfoByExternalUuid($data['uuid']);
if ($data['error'])
{
$errorType = static::getErrorType($data['error']['code']);
$result['ERROR'] = array(
'CODE' => $data['error']['code'],
'MESSAGE' => $data['error']['text'],
'TYPE' => ($errorType === Errors\Error::TYPE) ? Errors\Error::TYPE : Errors\Warning::TYPE
);
}
$result['ID'] = $checkInfo['ID'];
$result['CHECK_TYPE'] = $checkInfo['TYPE'];
$check = CheckManager::getObjectById($checkInfo['ID']);
$dateTime = new Main\Type\DateTime($data['payload']['receipt_datetime']);
$result['LINK_PARAMS'] = array(
Check::PARAM_REG_NUMBER_KKT => $data['payload']['ecr_registration_number'],
Check::PARAM_FISCAL_DOC_ATTR => $data['payload']['fiscal_document_attribute'],
Check::PARAM_FISCAL_DOC_NUMBER => $data['payload']['fiscal_document_number'],
Check::PARAM_FISCAL_RECEIPT_NUMBER => $data['payload']['fiscal_receipt_number'],
Check::PARAM_FN_NUMBER => $data['payload']['fn_number'],
Check::PARAM_SHIFT_NUMBER => $data['payload']['shift_number'],
Check::PARAM_DOC_SUM => $data['payload']['total'],
Check::PARAM_DOC_TIME => $dateTime->getTimestamp(),
Check::PARAM_CALCULATION_ATTR => $check::getCalculatedSign()
);
return $result;
}
/**
* @param $id
* @return array
*/
public function buildZReportQuery($id)
{
return array();
}
/**
* @param array $data
* @return array
*/
protected static function extractZReportData(array $data)
{
return array();
}
/**
* @return array
*/
protected function getCheckTypeMap()
{
return array(
SellCheck::getType() => 'sell',
SellReturnCashCheck::getType() => 'sell_refund',
SellReturnCheck::getType() => 'sell_refund'
);
}
/**
* @param $operation
* @param $token
* @param array $queryData
* @return string
* @throws Main\SystemException
*/
protected function getUrl($operation, $token, array $queryData = array())
{
$groupCode = $this->getField('NUMBER_KKM');
if ($operation === static::OPERATION_CHECK_REGISTRY)
{
return static::SERVICE_URL.'/'.$groupCode.'/'.$queryData['CHECK_TYPE'].'?tokenid='.$token;
}
elseif ($operation === static::OPERATION_CHECK_CHECK)
{
return static::SERVICE_URL.'/'.$groupCode.'/report/'.$queryData['EXTERNAL_UUID'].'?tokenid='.$token;
}
throw new Main\SystemException();
}
/**
* @param Check $check
* @return Result
*/
public function printImmediately(Check $check)
{
$printResult = new Result();
$token = $this->getAccessToken();
if ($token === '')
{
$token = $this->requestAccessToken();
if ($token === '')
{
$printResult->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_REQUEST_TOKEN_ERROR')));
return $printResult;
}
}
$checkQuery = static::buildCheckQuery($check);
$validateResult = $this->validate($checkQuery);
if (!$validateResult->isSuccess())
{
return $validateResult;
}
$operation = $check::getCalculatedSign() === Check::CALCULATED_SIGN_INCOME ? 'sell' : 'sell_refund';
$url = $this->getUrl(static::OPERATION_CHECK_REGISTRY, $token, array('CHECK_TYPE' => $operation));
$result = $this->send(static::REQUEST_TYPE_POST, $url, $checkQuery);
if (!$result->isSuccess())
return $result;
$response = $result->getData();
if ($response['http_code'] === static::RESPONSE_HTTP_CODE_401)
{
$token = $this->requestAccessToken();
if ($token === '')
{
$printResult->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_REQUEST_TOKEN_ERROR')));
return $printResult;
}
$url = $this->getUrl(static::OPERATION_CHECK_REGISTRY, $token, array('CHECK_TYPE' => $operation));
$result = $this->send(static::REQUEST_TYPE_POST, $url, $checkQuery);
if (!$result->isSuccess())
return $result;
$response = $result->getData();
}
if ($response['http_code'] === static::RESPONSE_HTTP_CODE_200)
{
if ($response['uuid'])
{
$printResult->setData(array('UUID' => $response['uuid']));
}
else
{
$printResult->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_CHECK_REG_ERROR')));
}
}
else
{
if (isset($response['error']['text']))
{
$printResult->addError(new Main\Error($response['error']['text']));
}
else
{
$printResult->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_CHECK_REG_ERROR')));
}
}
return $printResult;
}
/**
* @param Check $check
* @return Result
*/
public function check(Check $check)
{
$url = $this->getUrl(
static::OPERATION_CHECK_CHECK,
$this->getAccessToken(),
array('EXTERNAL_UUID' => $check->getField('EXTERNAL_UUID'))
);
$result = $this->send(static::REQUEST_TYPE_GET, $url);
if (!$result->isSuccess())
return $result;
$response = $result->getData();
if ($response['http_code'] === static::RESPONSE_HTTP_CODE_401)
{
$token = $this->requestAccessToken();
if ($token === '')
{
$result->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_REQUEST_TOKEN_ERROR')));
return $result;
}
$url = $this->getUrl(
static::OPERATION_CHECK_CHECK,
$this->getAccessToken(),
array('EXTERNAL_UUID' => $check->getField('EXTERNAL_UUID'))
);
$result = $this->send(static::REQUEST_TYPE_GET, $url);
if (!$result->isSuccess())
return $result;
$response = $result->getData();
}
if ($response['status'] === 'wait')
{
$result->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_REQUEST_STATUS_WAIT')));
return $result;
}
return static::applyCheckResult($response);
}
/**
* @param array $checkData
* @return Result
*/
protected function validate(array $checkData)
{
$result = new Result();
if ($checkData['receipt']['attributes']['email'] === '' && $checkData['receipt']['attributes']['phone'] === '')
{
$result->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_ERR_EMPTY_PHONE_EMAIL')));
}
foreach ($checkData['receipt']['items'] as $item)
{
if ($item['tax'] === null)
{
$result->addError(new Main\Error(Localization\Loc::getMessage('SALE_CASHBOX_ATOL_ERR_EMPTY_TAX')));
break;
}
}
return $result;
}
/**
* @param $method
* @param $url
* @param array $data
* @return Result
*/
private function send($method, $url, array $data = array())
{
$result = new Result();
$http = new Main\Web\HttpClient();
$http->setHeader('Content-Type', 'application/json; charset=utf-8');
if ($method === static::REQUEST_TYPE_POST)
{
$http->disableSslVerification();
$data = $this->encode($data);
$response = $http->post($url, $data);
}
else
{
$response = $http->get($url);
}
if ($response !== false)
{
try
{
$response = $this->decode($response);
if (!is_array($response))
$response = array();
$response['http_code'] = $http->getStatus();
$result->addData($response);
}
catch (Main\ArgumentException $e)
{
$result->addError(new Main\Error($e->getMessage()));
}
}
else
{
$error = $http->getError();
foreach ($error as $code =>$message)
{
$result->addError(new Main\Error($message, $code));
}
}
return $result;
}
/**
* @param int $modelId
* @return array
*/
public static function getSettings($modelId = 0)
{
$settings = array(
'AUTH' => array(
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_AUTH'),
'REQUIRED' => 'Y',
'ITEMS' => array(
'LOGIN' => array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_AUTH_LOGIN_LABEL')
),
'PASS' => array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_AUTH_PASS_LABEL')
),
)
),
'SERVICE' => array(
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_SERVICE'),
'REQUIRED' => 'Y',
'ITEMS' => array(
'INN' => array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_SERVICE_INN_LABEL')
),
'P_ADDRESS' => array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_SERVICE_URL_LABEL')
),
)
),
'CLIENT' => [
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_CLIENT'),
'ITEMS' => array(
'INFO' => array(
'TYPE' => 'ENUM',
'VALUE' => 'NONE',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_CLIENT_INFO'),
'OPTIONS' => array(
'NONE' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_CLIENT_NONE'),
'PHONE' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_CLIENT_PHONE'),
'EMAIL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_CLIENT_EMAIL'),
)
),
)
]
);
$settings['PAYMENT_TYPE'] = array(
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_P_TYPE'),
'REQUIRED' => 'Y',
'ITEMS' => array()
);
$systemPaymentType = array(
Check::PAYMENT_TYPE_CASH => 0,
Check::PAYMENT_TYPE_CASHLESS => 1,
);
foreach ($systemPaymentType as $type => $value)
{
$settings['PAYMENT_TYPE']['ITEMS'][$type] = array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_P_TYPE_LABEL_'.ToUpper($type)),
'VALUE' => $value
);
}
$settings['VAT'] = array(
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_BITRIX_SETTINGS_VAT'),
'REQUIRED' => 'Y',
'ITEMS' => array(
'NOT_VAT' => array(
'TYPE' => 'STRING',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_BITRIX_SETTINGS_VAT_LABEL_NOT_VAT'),
'VALUE' => 'none'
)
)
);
if (Main\Loader::includeModule('catalog'))
{
$dbRes = Catalog\VatTable::getList(array('filter' => array('ACTIVE' => 'Y')));
$vatList = $dbRes->fetchAll();
if ($vatList)
{
$defaultVat = array(0 => 'vat0', 10 => 'vat10', 18 => 'vat18', 20 => 'vat20');
foreach ($vatList as $vat)
{
$value = '';
if (isset($defaultVat[(int)$vat['RATE']]))
$value = $defaultVat[(int)$vat['RATE']];
$settings['VAT']['ITEMS'][(int)$vat['ID']] = array(
'TYPE' => 'STRING',
'LABEL' => $vat['NAME'].' ['.(int)$vat['RATE'].'%]',
'VALUE' => $value
);
}
}
}
$settings['TAX'] = array(
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_SNO'),
'REQUIRED' => 'Y',
'ITEMS' => array(
'SNO' => array(
'TYPE' => 'ENUM',
'LABEL' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SETTINGS_SNO_LABEL'),
'VALUE' => 'osn',
'OPTIONS' => array(
'osn' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_OSN'),
'usn_income' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_UI'),
'usn_income_outcome' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_UIO'),
'envd' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_ENVD'),
'esn' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_ESN'),
'patent' => Localization\Loc::getMessage('SALE_CASHBOX_ATOL_FARM_SNO_PATENT')
)
)
)
);
return $settings;
}
/**
* @return array
*/
public static function getGeneralRequiredFields()
{
$generalRequiredFields = parent::getGeneralRequiredFields();
$map = CashboxTable::getMap();
$generalRequiredFields['NUMBER_KKM'] = $map['NUMBER_KKM']['title'];
return $generalRequiredFields;
}
/**
* @return string
*/
private function getAccessToken()
{
return Main\Config\Option::get('sale', $this->getOptionName(), '');
}
/**
* @param $token
*/
private function setAccessToken($token)
{
Main\Config\Option::set('sale', $this->getOptionName(), $token);
}
/**
* @return string
*/
private function getOptionName()
{
return static::TOKEN_OPTION_NAME.'_'.ToLower($this->getField('NUMBER_KKM'));
}
/**
* @param array $data
* @return mixed
*/
private function encode(array $data)
{
return Main\Web\Json::encode($data);
}
/**
* @param string $data
* @return mixed
*/
private function decode($data)
{
return Main\Web\Json::decode($data);
}
/**
* @return string
*/
private function requestAccessToken()
{
$url = static::SERVICE_URL.'/getToken';
$data = array(
'login' => $this->getValueFromSettings('AUTH', 'LOGIN'),
'pass' => $this->getValueFromSettings('AUTH', 'PASS')
);
$result = $this->send(static::REQUEST_TYPE_POST, $url, $data);
if ($result->isSuccess())
{
$response = $result->getData();
$this->setAccessToken($response['token']);
return $response['token'];
}
return '';
}
/**
* @param $errorCode
* @throws Main\NotImplementedException
* @return int
*/
protected static function getErrorType($errorCode)
{
return Errors\Error::TYPE;
}
}