<?php
namespace Models;

class php_mspos_Fr_php {
	public $f3, $sets, $web, $config;

	public $new_smde=true;

    protected $ForcePrintForm=array(false, true);

    public $op_mode=array(
		0=>'Шифрование',
		1=>'Автономный режим',
		2=>'Автоматический режим',
		3=>'Применение в сфере услуг',
		4=>'Режим БСО',
		5=>'Применение в Интернет'
	);

	public $agent_tag=array(
		0=>'Банковский платежный агент',
		1=>'Банковский платежный субагент',
		2=>'Платежный агент',
		3=>'Платежный субагент',
		4=>'Поверенный',
		5=>'Комиссионер',
		6=>'Иной агент'
	);

	public $reg_data=array(
		6=>array('title'=>'Признак торговли подакцизными товарами', 'ffd'=>array('1.05', '1.1', '1.2'), 'tag'=>'1207'),
		8=>array('title'=>'Признак маркировки', 'ffd'=>array('1.2')),
		10=>array('title'=>'Проведение азартных игр', 'ffd'=>array('1.05', '1.1', '1.2'), 'tag'=>'1193'),
		11=>array('title'=>'Проведение лотереи', 'ffd'=>array('1.05', '1.1', '1.2'), 'tag'=>'1126'),
		12=>array('title'=>'Признак ломбарда', 'ffd'=>array('1.2')),
		13=>array('title'=>'Признак страхования', 'ffd'=>array('1.2'))
	);

	public $why_105=array(
		1=>'Замена ФН',
		2=>'Замена ОФД',
		3=>'Изменение реквизитов',
		4=>'Изменение настроек ККТ'
	);

	public $why_12=array(
		0=>'Замена ФН',
		1=>'Замена ОФД',
		2=>'Изменение наименования пользователя',
		3=>'Изменение адреса и/или места расчетов',
		4=>'Перевод из автономного режима в режим передачи данных',
		5=>'Перевод из режима передачи данных в автономный режим',
		6=>'Изменение версии модели ККТ',
		7=>'Изменение СНО',
		8=>'Изменение номера автомата',
		9=>'Перевод в неавтоматический режим',
		10=>'Перевод  в автоматический режим',
		11=>'Включение режима БСО',
		12=>'Отключение режима БСО',
		13=>'Отключение режима расчетов в сети Интернет',
		14=>'Включение режима расчетов в сети Интернет',
		15=>'Отключение режима агента',
		16=>'Включение режима агента',
		17=>'Отключение режима азартных игр',
		18=>'Включение режима азартных игр',
		19=>'Отключение режима лотереи',
		20=>'Включение режима лотереи',
		21=>'Изменение версии ФФД',
		31=>'Иные причины',
	);

	public $because_12=array(
		21=>'ffd'
	);

	public $ffd_version=array(
		//1=>'1.0',
		2=>'1.05',
		3=>'1.1',
		4=>'1.2'
	),
	$fn_status=array(
		0=>'Настройка',
		1=>'Готов к фискализации',
		3=>'Фискальный режим',
		7=>'Фискальный режим закрыт, идёт передача ОФД',
		15=>'Чтение данных из архива ФН'
	),
	$ofd_status=array(
		0=>'Нет соединения',
		1=>'Транспортное соединение установлено',
		2=>'Есть сообщение для передачи ОФД',
		4=>'Ожидание ответного сообщения (квитанции) от ОФД',
		8=>'Есть команда от ОФД',
		16=>'Изменились настройки соединения с ОФД',
		32=>'Ожидание ответа на команду от ОФД'
	),
	$day_status=array(
		0=>'Смена закрыта',
		1=>'Смена открыта'
	),
	$pay_type=array(
		0=>'Наличные',
		1=>'Безналичные',
		4=>'Баллы'
	),
	$sno=array(
		'01'=>1,
		'02'=>2,
		'04'=>4,
		'08'=>8,
		'10'=>16,
		'20'=>32
	);

	public $fd=0; // Номер ФД
	public $fp=0; // Фискальный признак
	public $kkm_time=0; // Время чека
	
	function __construct($f3, $sets, $config) {
		$this->f3=$f3;
		$this->sets=$sets;
		$this->web=\Web::instance();
        $this->config=$config;
        if(!isset($this->config['WaitTime'])) {
            $this->config['WaitTime']=30000;
        }
        if(!isset($this->config['FontSize'])) {
            $this->config['FontSize']=6;
        }
        if(!isset($this->config['FontBold'])) {
            $this->config['FontBold']=12;
        }
        $vat_type=array(
        	'vat20'=>1,
        	'vat10'=>2,
        	'vat120'=>3,
			'vat110'=>4,
			'vat0'=>5,
			'vatNo'=>6,
			'vat5'=>7,
			'vat7'=>8,
			'vat105'=>9,
            'vat107'=>10,
            'vat22'=>11,
			'vat122'=>12,
		);

		foreach($vat_type as $type=>$vat){
			if(!isset($this->config['vat_type'][$type])) {
            	$this->config['vat_type'][$type]=$vat;
        	}
		}
	}

	function kkm_init() {
		//$this->f3->set('SESSION.'.$this->sets['printer'].'_drivers_init', 1);
	}

	// Формирование данных для отправки
	function options($uuid, $data, $timeout=3) {
		$options = array( // Данные для отправки на сервер
			'timeout'=>$timeout,
			'header'=>array(
				'Content-Type: application/json',
        		'Expect:'
			),
    		'method'  => 'POST',
    		'content'=>json_encode(
    			array(
    				'uuid'=>$uuid,
    				'request'=>$data
    			)
    		)
		);

		return $options;
	}

	// Отправка задания
	function send_task($options) {
		$url=$this->sets['url'].'/requests';
		$res=$this->web->request($url, $options);
		$json=json_decode($res['body'], true);
		if(!$res['headers'] || (mb_strpos($res['headers'][0], '200')===false && mb_strpos($res['headers'][0], '201')===false)) {
			if(is_array($json) && $json['result']) {
				$error_txt='Код ошибки '.$json['result'][0]['error']['code'].'. '.$json['result'][0]['error']['description'];
			}
			elseif(is_array($json)) {
				$error_txt='Код ошибки '.$json['error']['code'].'. '.$json['error']['description'];
			}
			elseif($res['body']) {
				$error_txt=$res['body'];
			}
			else {
				$error_txt='Нет соединения. Проверьте включен ли кассовый аппарат и/или проверьте провод от аппарата до компьютера. Попробуйте выключить и включить кассовый аппарат.';
			}
			$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error', 'error');
			if($this->f3->get('fr_error_ignore')) {
                return array(
                    'success'=>false,
					'error'=>$error_txt
                );
            }
            echo $error_txt;
			exit();
		}
		return array(
			'success'=>true,
			'data'=>$json
		);
	}

	function check_task($uuid) {
		$url=$this->sets['url'].'/requests/'.$uuid;
		$options=array(
			'timeout'=>3,
			'method'=>'GET'
		);
		// Ждем выполнения задания
		$ok=false;
		$error='';
		$n=200;
		for($i=0; $i<$n; $i++) {
			usleep($this->config['WaitTime']);
			$res=$this->web->request($url, $options);
			$json=json_decode($res['body'], true);
			if(mb_strpos($res['headers'][0], '200')===false && mb_strpos($res['headers'][0], '201')===false) {
				if(is_array($json) && $json['result']) {
					$error_txt.='Код ошибки '.$json['result'][0]['error']['code'].'. '.$json['result'][0]['error']['description'].'<br>';
				}
				elseif(is_array($json)) {
					$error_txt.='Код ошибки '.$json['error']['code'].'. '.$json['error']['description'].'<br>';
				}
				else {
					$error_txt=$res['body'];
				}
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error', 'error');
				if($this->f3->get('fr_error_ignore')) {
	                return array(
	                    'success'=>false,
						'error'=>$error_txt
	                );
	            }
	            echo $error_txt;
	            $this->send_ajax('g;');
				exit();
			}
			// Проверяем результаты заданий
			$ready=0;
			$wait=1;
			foreach ($json['results'] as $r) {
				if($r['status']=='ready') { // Задание выполнено
					$ready=1;
					$wait=0;
					if($r['error']['code']>0) {
						$ok=false;
					}
					
					
				}
				if($r['status']=='wait') { // Задание ждет очереди или еще выполняется
					$ready=0;
				}
				if($r['status']=='error') { // Ошибка выполнения задания, дальше ничего не выполнится
					$this->f3->get('logs_model')->save_log($r['error'].' (Касса)', 'error');
                    $error_txt.='<p class="false">'.$r['error']['description'].'</p>';
					$i=$n;
					$ready=0;
					$wait=0;
					break;
				}
			}
			if($ready==1) {
				$i=$n;
				$ok=true;
			}
		}
		if($wait==1) {
			$ok=false;
			$json['results'][0]['error']['code']=9999;
			$json['results'][0]['error']['description']='Не удалось дождаться выполнения задания ';
		}
		if($ok===false) { // Вывод ошибок
			$g=true;
			foreach ($json['results'] as $a=>$r) {
				if($r['error']['code']==995) $g=false;
				$error.='<p class="false">Код ошибки '.$r['error']['code'].'. '.$r['error']['description'].'</p>';
			}
			if($g)$this->send_ajax('g;');
			$this->f3->get('logs_model')->save_log($error.' (Касса)', 'error');
		}
		return array(
			'success'=>$ok,
			'error'=>$error,
			'results'=>$json['results']
		);
	}

	// Выводим статус ККМ в понятном виде
	function deviceStatus($data) {
		$txt=array(
			'group_1'=>'Статус ККТ',
			'GetRegNum'=>'Регистрационный номер ККТ',
			'GetSerial'=>'Заводской номер ККТ (ЗН)',
			'GetAppVersion'=>'Версия ПО ядра',
			'GetTaxId'=>'ИНН, указанный при регистрации',
			'GetOrgName'=>'Наименование организации',
			'GetOrgAddress'=>'Адрес организации',
			'GetPhysicalAddress'=>'Место расчетов',
			'GetKKTRegisteredName'=>'Название ККТ в реестре',
			'group_2'=>'Запрос сменных счётчиков по типам документов и оплат',
			'group_3'=>'Документы продажи',
			'GetDayPayTotalByDocType_1_5'=>'Наличные',
			'GetDayPayTotalByDocType_1_6'=>'Безналичные',
			'group_4'=>'Документы возврата продажи',
			'GetDayPayTotalByDocType_2_5'=>'Наличные',
			'GetDayPayTotalByDocType_2_6'=>'Безналичные',
			'group_5'=>'',
			'GetFiscalMemoryFiscalized'=>'Статус фискализации ККТ в фискальной памяти (ФП)',
			'group_6'=>'Запрос счётчиков накоплений на начало смены по типу счётчика',
			'GetGrandTotalsSalesGross_1'=>'Документы продажи',
			'GetGrandTotalsSalesGross_2'=>'Документы возврата продажи',
			'group_7'=>'',
			'GetCurrentFfdVersion'=>'Версия ФФД',
			'GetKktVersion'=>'Версия модели',
			'GetKktFfdVersion'=>'Максимальная версия ФФД поддерживаемая ККТ',
			'group_8'=>'Статус ФН',
			'FNGetNumber'=>'Номер ФН',
			'FNGetState'=>'Состояние ФН',
			'FNGetCurrentDocType'=>'Текущий документа из ФН',
			'FNGetLastDocDateTime'=>'Дата и время последнего фискального документа',
			'FNGetSoftwareVersion'=>'Версия ПО ФН',
			'FNGetFirmwareType'=>'Тип ПО ФН',
			'FNGetLastFDNumber'=>'Номер последнего фискального документа',
			'FNGetLifetime'=>'Дата и время окончания действия ФН',
			'FNGetRegistrationsLeft'=>'Количество оставшихся регистраций ФН',
			'FNGetRegistrationsMade'=>'Количество выполненных регистраций ФН',
			'FNGetRegTimeFirst'=>'Время первой регистрации (фискализации) ФН',
			'FNGetLastFiscalSign'=>'ФП последнего фискального документа',
			'FNGetFnFfdVersion'=>'Код версии ФФД, которую может поддерживать ФН',
			'group_9'=>'Состояние ОФД',
			'OFDGetConnectionStatus'=>'Состояние соединения с ОФД',
			'OFDGetQueuedMessagesCount'=>'Количество документов, ожидающих отправки в ОФД',
			'OFDGetFirstQueuedDocNumber'=>'Номер документа, находящегося первым в очереди на отправку в ОФД',
			'OFDGetLastNotSentDocTime'=>'Дата последнего непереданного в ОФД документа',
			'group_10'=>'Состояние смены',
			'GetDayState'=>'Состояние смены в ККТ',
			'GetDayNumber'=>'Номер смены',
			'GetDayLastReceiptNumber'=>'Номер последнего документа в смене'
		);
		foreach($txt as $key=>$title) {
			if(!isset($data[$key])) {
				echo '<h1>'.$title.'</h1>';
			}
			else {
				if($key=='FNGetNumber') {
					$this->f3->set('fn', $data[$key]);
				}
				if($key=='GetFiscalMemoryFiscalized') {
					if($data[$key]) {
						$data[$key]='фискальная память фискализирована';
					}
					else {
						$data[$key]='фискальная память не фискализирована';
					}
				}
				elseif($key=='GetCurrentFfdVersion' || $key=='GetKktFfdVersion' || $key=='FNGetFnFfdVersion') {
					$data[$key]=$this->ffd_version[$data[$key]];
				}
				elseif($key=='FNGetState') {
					$data[$key]=$this->fn_status[hexdec($data[$key])];
				}
				elseif($key=='OFDGetConnectionStatus') {
					$data[$key]=$this->ofd_status[hexdec($data[$key])];
				}
				elseif($key=='GetDayState') {
					$data[$key]=$this->day_status[hexdec($data[$key])];
				}
				echo '<p><b>'.$title.'</b>: '.$data[$key].'</p>';
			}
		}
	}

	// Отправка запроса
	function send_ajax($strs, $timeout=3, $view=false) {
		/*if(!$this->f3->get('SESSION.'.$this->sets['printer'].'_drivers_init')) {
			$this->kkm_init();
		}*/
		$data=$this->wtf($strs);
		if(!$data) {
			$error_txt=$strs.': Команда не поддерживается';
			$this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
			if($this->f3->get('fr_error_ignore')) {
                return array(
                    'success'=>false,
					'error'=>$error_txt
                );
            }
			echo '<p class="false">'.$error_txt.'</p>';
			exit();
		}

		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);

		$cmd=array_column($data, 0);
		$CloseRec_n=array_search('CloseRec', $cmd);
		if($CloseRec_n>0) {
			if($res['results'][0]['result'][$CloseRec_n]=='ok') {
				$fn_n=array_search('FNGetLastFDNum', $cmd);
				if($fn_n>0) {
					$res['fd']=$res['results'][0]['result'][$fn_n];
					$this->fd=$res['fd'];
				}
				$fp_n=array_search('FNGetLastFiscalSign', $cmd);
				if($fp_n>0) {
					$res['fp']=$res['results'][0]['result'][$fp_n];
					$this->fp=$res['fp'];
				}
				$kkm_time_n=array_search('FNGetLastDocDateTime', $cmd);
				if($kkm_time_n>0) {
					$res['kkm_time']=strtotime($res['results'][0]['result'][$kkm_time_n]);
					$this->kkm_time=$res['kkm_time'];
				}
			}
		}
		if($this->fd>0 || $this->fp>0) {
			$res['success']=true;
		}

		if(!$res['success']) {
			$error_txt.=$strs.'<br>';
			$error_txt.=$res['error'];
			$this->f3->get('logs_model')->save_log($strs.': '.$res['error'].' (Касса)', 'error');
			if($this->f3->get('fr_error_ignore')) {
                return array(
                    'success'=>false,
					'error'=>$error_txt
                );
            }
            echo $error_txt;
			exit();
		}
		$check_mark_n=array_search('SaveMarkupCodeCheckResult', $cmd);

		if($check_mark_n>0) {
			$mark_result=$res['results'][0]['result'][$check_mark_n];
			$success_status=array(12, 13, 15, 28, 29, 31);
			if(!in_array($mark_result, $success_status)) {
				$errors=array(
					0=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					1=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					3=>'Результат проверки КП КМ положительный. Сведения о статусе товара от ОИСМ не получены',
					4=>'От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					5=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					7=>'Результат проверки КП КМ положительный. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					16=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					17=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					19=>'Результат проверки КП КМ положительный. Сведения о статусе товара от ОИСМ не получены',
					20=>'От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					21=>'Результат проверки КП КМ отрицательный или код маркировки не был проверен. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены',
					23=>'Результат проверки КП КМ положительный. От ОИСМ получены сведения, что планируемый статус товара некорректен или сведения о статусе товара от ОИСМ не получены'
				);
				if($errors[$mark_result]) {
					$error=$errors[$mark_result];
				}
				else {
					$error="Неизвестная ошибка";
				}
				$this->f3->get('logs_model')->save_log($error.' (Касса)', 'error');
				return array(
					'success'=>false,
					'marking_error'=>true,
					'txt'=>$error,
				);
			}
		}
		
		if($view) {
			foreach ($res['results'] as $key=>$r) {
				if($DeviceInfo) {
					$this->deviceStatus($DeviceInfo);
				}
				elseif($r['result']) {
					if($r['error']['code']) {
						echo '<p class="false">'.$r['error']['description'].'</p>';
						$this->f3->get('logs_model')->save_log($r['error']['description'].' (Касса)', 'error');
					}
					else {
						echo '<p class="true">Выполнено успешно</p>';
					}
				}
			}
		}
		if(!$res['success'] && !$view) {
			if($this->f3->get('fr_error_ignore')) {
                return array(
                    'success'=>false,
					'error'=>$error
                );
            }
			echo $continue_html= \Template::instance()->render('fr_error.htm');
			exit();
		}
		$this->fd=0;
		$this->fp=0;

		return $res;
	}

	function get_fn_status(){
		$data=array(
			array('FNGetState')
		);
		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		if($res['success']) {
			// Проверка выполнения задания
			$res=$this->check_task($uuid);
		}
		if(!$res['success']) {
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			if($this->f3->get('fr_error_ignore')) {
				return $res;
			}
			echo $res['error'];
			exit();
		}
		return $res['results'][0]['result'][0];
	}

	// Информация о ККМ
	function getDeviceInfo() {
		$fn_status=$this->get_fn_status();

		$data=array(
			array('GetRegNum'),
			array('GetSerial'),
			array('GetAppVersion'),
			array('GetTaxId'),
			array('GetOrgName'),
			array('GetOrgAddress'),
			array('GetKKTRegisteredName'),
			array('GetDayPayTotalByDocType', 1, 5),
			array('GetDayPayTotalByDocType', 1, 6),
			array('GetDayPayTotalByDocType', 2, 5),
			array('GetDayPayTotalByDocType', 2, 6),
			array('GetFiscalMemoryFiscalized'),
			array('GetGrandTotalsSalesGross', 1),
			array('GetGrandTotalsSalesGross', 2),
			array('GetCurrentFfdVersion'),
			array('GetKktVersion'),
			array('GetKktFfdVersion'),
			array('FNGetNumber'),
			array('FNGetState'),
			array('FNGetCurrentDocType'),
			array('FNGetLastDocDateTime'),
			array('FNGetSoftwareVersion'),
			array('FNGetFirmwareType'),
			array('FNGetLastFDNumber'),
			array('FNGetLifetime'),
			array('FNGetRegistrationsLeft')
		);

		if($fn_status!=1) {
			$data[]=array('FNGetRegistrationsMade');
			$data[]=array('FNGetRegTimeFirst');
			$data[]=array('FNGetLastFiscalSign');
			$data[]=array('FNGetFnFfdVersion');
			$data[]=array('OFDGetConnectionStatus');
			$data[]=array('OFDGetQueuedMessagesCount');
			$data[]=array('OFDGetFirstQueuedDocNumber');
			$data[]=array('OFDGetLastNotSentDocTime');
			$data[]=array('GetDayState');
			$data[]=array('GetDayNumber');
			$data[]=array('GetDayLastReceiptNumber');
		}
		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		if($res['success']) {
			// Проверка выполнения задания
			$res=$this->check_task($uuid);
		}
		if(!$res['success']) {
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			if($this->f3->get('fr_error_ignore')) {
				return $res;
			}
			echo $res['error'];
			exit();
		}
		$result=array();
		foreach($res['results'][0]['result'] as $n=>$r) {
			$key=$data[$n][0];
			if(isset($data[$n][1])) {
				$key.='_'.$data[$n][1];
			}
			if(isset($data[$n][2])) {
				$key.='_'.$data[$n][2];
			}
			$result[$key]=$r;
		}
		return $result;
	}

	function get_ofd() {
		$data=array(
			array('GetCurrentFfdVersion'),
			array('GetOfdName'),
			array('GetOfdTaxId'),
			array('GetOfdHost'),
			array('GetOfdPort'),
			array('GetOismHost'),
			array('GetOismPort'),
			array('GetKeyServerHost'),
			array('GetKeyServerPort')
		);
		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		$result=array();
		foreach($res['results'][0]['result'] as $n=>$r) {
			$key=$data[$n][0];
			$result[$key]=trim($r);
		}
		return $result;
	}

	function set_ofd($data) {
		$cmd=array(
			array('SetOfdName', $data['ofd_name']),
			array('SetOfdTaxId', $data['ofd_taxid']),
			array('SetOfdHost', $data['ofd_host']),
			array('SetOfdPort', $data['ofd_port']),
			array('SetCompactMode', 1)
		);

		if(isset($data['oism_port']) && isset($data['oism_port'])) {
			$cmd[]=array('SetOismHost', $data['oism_host']);
			$cmd[]=array('SetOismPort', $data['oism_port']);
		}

		if(isset($data['key_host']) && isset($data['key_port'])) {
			$cmd[]=array('SetKeyServerHost', $data['key_host']);
			$cmd[]=array('SetKeyServerPort', $data['key_port']);
		}

		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $cmd, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful'
		);
	}

	function get_regdata(){
		$fn_status=$this->get_fn_status();
		if($fn_status==1) {
			return array('fn_status'=>$fn_status);
		}
		// 7838381318
		// 0000000000024066
		$data=array(
			array('GetDayState'),
			array('GetOrgName'),
			array('GetOrgAddress'),
			array('GetPhysicalAddress'),
			array('GetSenderEmail'),
			array('GetFNSServerAddress'),
			array('GetCashierTaxId'),
			array('GetVendingSerial'),
			array('GetTaxId'),
			array('GetRegNum'),
			array('GetUserName'),
			array('GetTaxation'),
			array('GetAgentTag'),
			array('GetCurrentFfdVersion'),
			array('FNGetRegistrationsMade')
		);
		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		$result=array();
		foreach($res['results'][0]['result'] as $n=>$r) {
			$key=$data[$n][0];
			$result[$key]=trim($r);
		}

		$data=array(
			array('FNGetOpModeByNum', $result['FNGetRegistrationsMade'])
		);

		if($this->ffd_version[$result['GetCurrentFfdVersion']]=='1.2') {
			$data[]=array('GetRegistrationParameter', $result['FNGetRegistrationsMade'], '1290');
		}
		else {
			$reg_data_index=array();
			foreach($this->reg_data as $n=>$d){
				if($d['tag']) {
					$data[]=array('GetRegistrationParameter', $result['FNGetRegistrationsMade'], $d['tag']);
					$reg_data_index[]=$n;
				}
			}
		}

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		foreach($res['results'][0]['result'] as $n=>$r) {
			$key=$data[$n][0];
			if($key=='GetRegistrationParameter') {
				$result[$key][]=trim($r);
			}
			else {
				$result[$key]=trim($r);
			}
		}
		$GetTaxation=str_split(strrev((string)decbin($result['GetTaxation'])), 1);
		foreach($GetTaxation as $n=>$val){
			$n=dechex(bindec('1'.str_repeat('0', max($n, 0))));
			if($n<10)$n='0'.$n;
			$result['Taxation'][(string)$n]=$val;
		}
		$result['AgentTag']=str_split(strrev((string)decbin($result['GetAgentTag'])), 1);
		$result['OpMode']=str_split(strrev((string)decbin($result['FNGetOpModeByNum'])), 1);
		if($this->ffd_version[$result['GetCurrentFfdVersion']]=='1.2') {
			$result['RegData']=str_split(strrev((string)decbin($result['GetRegistrationParameter'][0])), 1);
		}
		else {
			foreach($result['GetRegistrationParameter'] as $n=>$value){
				$result['RegData'][$reg_data_index[$n]]=$value;
			}
		}
		$result['fn_status']=$fn_status;
		return $result;
	}

	function closefn() {
		$fn_status=$this->get_fn_status();
		if($fn_status==1) {
			return array(
				'success'=>false,
				'txt'=>'fn_not_registr'
			);
		}
		if($fn_status==7) {
			return array(
				'success'=>false,
				'txt'=>'fn_closed'
			);
		}
		if($this->change_status()==1) {
			return array(
				'success'=>false,
				'txt'=>'need_close_change'
			);
		}

		$data=array(
			array('CloseFiscalMode')
		);

		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'fn_closed_successful'
		);
	}

	function kkm_registration($reg_data) {
		$fn_status=$this->get_fn_status();
		if($fn_status==7) {
			return array(
				'success'=>false,
				'txt'=>'fn_closed'
			);
		}

		$registr=array(
			'1.05'=>'Register',
			'1.1'=>'Register1_1',
			'1.2'=>'Register1_2',
		);

		$correct_registr=array(
			'1.05'=>'CorrectRegistration',
			'1.1'=>'CorrectRegistration1_1',
			'1.2'=>'CorrectRegistration1_2',
		);

		if($fn_status==1) {
			if(!$this->get_ofd()['GetOfdName']) {
				return array(
					'success'=>false,
					'txt'=>'need_set_ofd'
				);
			}
			$method=$registr[$reg_data['ffd']];
		}
		else {
			if($this->change_status()==1) {
				return array(
					'success'=>false,
					'txt'=>'need_close_change'
				);
			}
			$method=$correct_registr[$reg_data['ffd']];
		}

		$sno_bin='';
		foreach($this->sno as $key=>$sno) {
			if($reg_data['sno'][$key]==1) {
				$sno_bin.='1';
			}
			else {
				$sno_bin.='0';
			}
		}
		$reg_data['sno']=bindec(strrev($sno_bin));

		$op_mode_bin='';
		foreach($this->op_mode as $key=>$op_mode) {
			if($reg_data['op_mode'][$key]==1) {
				$op_mode_bin.='1';
			}
			else {
				$op_mode_bin.='0';
			}
		}
		$reg_data['op_mode']=bindec(strrev($op_mode_bin));

		$agent_tag_bin='';
		foreach($this->agent_tag as $key=>$agent_tag) {
			if($reg_data['agent_tag'][$key]==1) {
				$agent_tag_bin.='1';
			}
			else {
				$agent_tag_bin.='0';
			}
		}
		$reg_data['agent_tag']=bindec(strrev($agent_tag_bin));

		$why_1_2_bin='';
		foreach($this->why_12 as $key=>$why) {
			if($reg_data['why']['1.2'][$key]==1) {
				$why_1_2_bin.='1';
			}
			else {
				$why_1_2_bin.='0';
			}
		}

		$reg_data['why']['1.2']=bindec(strrev($why_1_2_bin));
		foreach($reg_data as $key=>$value){
			if(is_array($value)) {
				foreach($value as $key_value=>$val){
					$reg_data[$key][$key_value]=trim($val);
				}
			}
			else {
				$reg_data[$key]=trim($value);
			}
		}

		// Настройка организации
		$res=$this->set_organization($reg_data);
		if(!$res['success']) {
			return $res;
		}

		if(!$method) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}

		return $this->$method($reg_data);
	}

	function set_organization($reg_data) {
		$data=array(
			array('SetOrgName', $reg_data['orgname']),
			array('SetOrgAddress', $reg_data['orgaddress']),
			array('SetPhysicalAddress', $reg_data['physicaladdress']),
			array('SetSenderEmail', $reg_data['senderemail']),
			array('SetFnsServerAddress', $reg_data['fnsserver']),
			array('SetCashierTaxId', $reg_data['cashiertaxid']),
			array('SetUserName', $reg_data['username']),
			array('SetVendingSerial', $reg_data['vendingserial']),
			array('SaveOptions')
		);


		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful'
		);
	}

	function Register($reg_data) {
		$data=array();
		if($reg_data['reg_data'][6]) {
			$data[]=array('SetTagAttribute', 1207, 1);
		}
		$data[]=array('Register', $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['agent_tag']);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	function Register1_1($reg_data) {
		$data=array();
		if($reg_data['reg_data'][6]) {
			$data[]=array('SetTagAttribute', 1207, 1);
		}
		$data[]=array('Register1_1', $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['agent_tag']);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	function Register1_2($reg_data) {
		$data=array(
			array('Register1_2', $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['reg_data'][6]?true:false, $reg_data['reg_data'][8]?true:false, $reg_data['reg_data'][12]?true:false, $reg_data['reg_data'][13]?true:false)
		);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	function CorrectRegistration($reg_data) {
		$data=array();
		if($reg_data['reg_data'][6]) {
			$data[]=array('SetTagAttribute', 1207, 1);
		}
		$data[]=array('CorrectRegistration', (int)$reg_data['why']['1.05'], $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['agent_tag']);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	function CorrectRegistration1_1($reg_data) {
		$data=array();
		if($reg_data['reg_data'][6]) {
			$data[]=array('SetTagAttribute', 1207, 1);
		}
		$data[]=array('CorrectRegistration1_1', (int)$reg_data['why']['1.2'], $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['agent_tag']);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	function CorrectRegistration1_2($reg_data) {
		$data=array(
			array('CorrectRegistration1_2', (int)$reg_data['why']['1.2'], $reg_data['username'], $reg_data['taxid'], $reg_data['regnum'], $reg_data['sno'], $reg_data['op_mode'], $reg_data['reg_data'][10]?true:false, $reg_data['reg_data'][11]?true:false, $reg_data['reg_data'][6]?true:false, $reg_data['reg_data'][8]?true:false, $reg_data['reg_data'][12]?true:false, $reg_data['reg_data'][13]?true:false)
		);

		$uuid=uniqid();
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

    // Узнаем состояние смены
    function change_status() {
        $data=array(
			array('GetDayState'),
			array('FNGetNumber'),
			array('GetDayOpenDateTime'),
		);
		$uuid=uniqid(); // id задания
		$options = $this->options($uuid, $data, 10);
		// Отправляем запрос
		$res=$this->send_task($options);
		// Проверка выполнения задания
		$res=$this->check_task($uuid);
		if(!$res['success']) {
			echo $res['error'];
			$this->f3->get('logs_model')->save_log($res['error'].' (Касса)', 'error');
			exit();
		}
		$result=array();
		foreach($res['results'][0]['result'] as $n=>$r) {
			$key=$data[$n][0];
			$result[$key]=$r;
		}

        $this->f3->set('fn', $result['FNGetNumber']);
        if($result['GetDayState']==1) {
        	$status='opened';
        	$open_time=strtotime($result['GetDayOpenDateTime']);
        	$open_time_h=(time()-$open_time)/3600;
        	if($open_time_h>=24) {
        		$status='expired';
        	}
        }
        else {
        	$status='closed';
        }
        // closed - закрыта
        // opened - открыта
        // expired - истекла
        return $status;
    }

    function check_fnstatus() {
        $res=$this->getDeviceInfo();
        return array(
            'success'=>true,
            'kkm'=>'MS-Pos',
            'ffd'=>$this->sets['version'],
            'inn'=>$res['GetTaxId'],
            'kpp'=>'',
            'org_name'=>$res['GetOrgName'],
            'org_address'=>$res['GetOrgAddress'],
            'ofd_n'=>$res['OFDGetQueuedMessagesCount'],
            'fn_end'=>strtotime($res['FNGetLifetime'])
        );
    }

	// Форматирование текста
    function text_format($str, $w=0) {
    	$lines=array();
    	$str=str_replace('#kkm_br##kkm_right#', '#kkm_right#', $str);
    	$str=str_replace('#kkm_br##kkm_center#', '#kkm_center#', $str);
    	$str=str_replace('#kkm_right#', '#kkm_br##kkm_right#', $str);
    	$str=str_replace('#kkm_center#', '#kkm_br##kkm_center#', $str);
    	$strs=explode('#kkm_br#', $str);
    	foreach($strs as $s) {
    		$bold=0;
    		$align=0;
    		if(mb_strpos($s, '#kkm_bold')!==false) {
    			$bold=1;
    			$s=str_replace('#kkm_bold#', '', $s);
    			$lines[]=array(
        			'SetFont',
        			$this->config['FontSize']*2
        		);
    		}
    		if(mb_strpos($s, '#kkm_center')!==false) {
    			$align=1;
    			$s=str_replace('#kkm_center#', '', $s);
    		}
    		elseif(mb_strpos($s, '#kkm_right')!==false) {
    			$align=2;
    			$s=str_replace('#kkm_right#', '', $s);
    		}
    		if(!$s) continue;
    		if($w>0) {
    			$str=mb_str_split($s, $w);
    		}
    		else {
    			$str=array($s);
    		}
    		foreach($str as $s) {
    			if(!$s) $s=' ';
    			$lines[]=array(
					'PrintLine',
					$align,
        			$s
        		);
    		}

        	if($bold==1) {
        		$lines[]=array(
        			'SetFont',
        			$this->config['FontSize']
        		);
        	}
    	}

    	return $lines;
    }

	// Что надо выполнить
	function wtf($strs) {
		$str=explode("\n", $strs);
		$open=false;
		$open_type=false;
		$ticket_sum=0;
		$correct_data=array(
			'AddCorrectionRecItem1_1',
        	-1,
        	date('Y-m-d').'T'.date('H:i:s').'.000Z',
        	''
        );
		$data[]=array(
        	'SetFont',
        	$this->config['FontSize']
        );
        $clearmark=false;
		foreach ($str as $s) {
			$items=array();
			$s=trim($s);
        	$p=explode(';', $s);
        	$n=count($p);
        	if($p[$n-1]=='') {
            	unset($p[$n-1]);
            	$n-=1;
        	}
        	if($s=='') continue;
        	if($p[0]=='beep') { // Гудок
        		if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data[]=array(
        			'PrintLine',
        			0,
        			'Бип-бип-бип! Твой сигналит джип'
        		);
        	}
        	elseif($p[0]=='feed') { // Протяжка
        		if(!$open) {
        			$open=true;
        			$open_type=9;
	        		$data[]=array(
	        			'OpenRec',
	        			9
	        		);
	        	}
                $data[]=array(
                    'Feed',
                    $p[1]
                );
        	}
        	elseif($p[0]=='g') {
        		$data[]=array(
        			'RecVoid'
        		);
        	}
        	elseif($p[0]=='open_session') { // Открытие смены
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$cashier_name='';
        		if(!isset($p[1]))$p[1]=1;
        		$data[]=array(
					'ForcePrintForm',
					$this->ForcePrintForm[$p[1]]
				);
        		if(isset($p[2])) {
        			$cashier=explode('{{user_inn}}', $p[2]);
        			$cashier_name=$cashier[0];
        		}
        		$data[]=array(
        			'OpenDay',
        			$cashier_name
        		);
        	}
        	elseif($p[0]=='z') { // Закрытие смены
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		if(!isset($p[1]))$p[1]=1;
        		$data[]=array(
					'ForcePrintForm',
					$this->ForcePrintForm[$p[1]]
				);
                $cashier_name='';
        		if(isset($p[2])) {
        			$cashier=explode('{{user_inn}}', $p[2]);
        			$cashier_name=$cashier[0];
        		}
        		$data[]=array(
        			'CloseDay',
        			$cashier_name
        		);
        	}
        	elseif ($p[0]=='p') { // Печать текста
        		if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data=array_merge($data, $this->text_format($p[1]));
        	}
        	elseif ($p[0]=='pm') { // Печать текста
        		if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data=array_merge($data, $this->text_format($p[2], $p[1]));
        	}
            elseif ($p[0]=='qr') { // Печать текста

                $data[]=array(
                	'PrintQRCode',
                	$p[1],
                	1
                );
            }
            elseif ($p[0]=='barcode') { // Печать текста
            	if(mb_strlen($p[1])==8) {
		            $code_type=3;
		        }
		        else {
		            $code_type=2;
		        }
                $data[]=array(
                	'PrintBarCode',
                	$code_type,
                	1,
                	(string)$p[1]
                );

                
                if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data=array_merge($data, $this->text_format('#kkm_center#'.$p[1]));
            }
        	elseif($p[0]=='print_font') { // Печать строки заданным размером шрифта
        		if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data[]=array(
        			'SetFont',
        			$p[1]
        		);
        		$data=array_merge($data, $this->text_format($p[2]));
        		$data[]=array(
        			'SetFont',
        			$this->config['FontSize']
        		);
        	}
        	elseif($p[0]=='print_bold') { // Печать жирной строки
        		if(!$open) {
        			$open=true;
        			$open_type=9;
        			$data[]=array(
        				'OpenRec',
        				9
        			);
        		}
        		$data[]=array(
        			'SetFont',
        			$this->config['FontBold']
        		);
        		$data=array_merge($data, $this->text_format($p[1]));
        		$data[]=array(
        			'SetFont',
        			$this->config['FontSize']
        		);
        	}
        	elseif($p[0]=='x') { // X отчет
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$data[]=array(
        			'PrintCalculationsReport'
        		);
        	}
        	elseif($p[0]=='continue_print') { // Продолжить печать чека
        		$data[]=array(
        			'RecVoid'
        		);
        	}
        	elseif($p[0]=='c') { // Печать копии последнего чека
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$data[]=array(
        			'PrintRecCopy'
        		);
        	}
        	elseif($p[0]=='printdoc') {
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$data[]=array(
        			'FNPrintDocFromArchive',
        			$p[1]
        		);
        	}
        	elseif($p[0]=='d') { // Статус ККМ
            	$this->deviceStatus($this->getDeviceInfo());
            	exit();
        	}
        	elseif($p[0]=='imde') { // Внесение или изъятие из кассы
        		$type=7;
        		if($p[1]<0){
        			$p[1]=abs($p[1]);
        			$type=8;
        		}
        		if($open) {
        			$open=false;
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$data[]=array(
        			'OpenRec',
        			$type
        		);
        		$data[]=array(
        			'PrintRecItem',
        			1,
        			number_format($p[1]/100, 2, '.', ''),
        			'Внесение/Изъятие',
        			' '
        		);
        		$data[]=array(
        			'PrintRecTotal'
        		);
        		$data[]=array(
        			'PrintRecItemPay',
        			0,
        			number_format($p[1]/100, 2, '.', ''),
        			$this->pay_type[0]
        		);
        		$data[]=array(
        			'CloseRec'
        		);
        	}
        	elseif($p[0]=='b') { // Открытие чека
        		if($open) {
        			$data[]=array(
        				'CloseRec'
        			);
        		}
        		$data[]=array(
					'ForcePrintForm',
					$this->ForcePrintForm[$p[3]]
				);
        		$cashier=explode('{{user_inn}}', $p[2]);
        		if($cashier[0]) {
        			$data[]=array(
        				'SetUserName',
        				$cashier[0]
        			);
        		}

        		$types=array(0=>1, 1=>3, 128=>21, 130=>23);
        		$data[]=array(
        			'SetTaxationUsing',
        			$this->sno[$this->sets['sno']]
        		);
        		$data[]=array(
        			'OpenRec',
        			$types[$p[1]]
        		);
        		if($types[$p[1]]>=21 && $types[$p[1]]<=24) {
        			$correct=true;
        			$correct_data[1]=0;
        		}
        		$open=true;
        		$open_type=$types[$p[1]];
        		$ticket_sum=$p[4];
        	}
        	elseif($p[0]=='set_tlv' && $p[1]==1173 && $open===true) { // Тип коррекции
        		$correct_data[1]=$p[3];
        	}
        	elseif($p[0]=='set_tlv' && $p[1]==1178 && $open===true) { // Дата коррекции
        		$correct_data[2]=date('Y-m-d', $p[3]).'T'.date('H:i:s', $p[3]).'.000Z';
        	}
        	elseif($p[0]=='set_tlv' && $p[1]==1179 && $open===true) { // Номер документа коррекции
        		$correct_data[3]=(string)$p[3];
        	}
        	elseif($p[0]=='set_tlv' && $p[1]==1192 && $open===true) { // ФПД ошибочного чека
        		$data[]=array(
	               	'SetTagAttribute',
					1192,
					$p[3]
				);
        	}
        	elseif($p[0]=='partner') {
        		$partner=json_decode($p[1], true);
        		if($partner['ur']==1) {
	        		$data[]=array(
	            		'SetSTLVTagAttribute',
						1256,
						array(1227, 1228),
						array($partner['name'], $partner['inn'])
	            	);
	            }
            	if($partner['client']) {
            		if(mb_strpos($partner['client'], '@')===false) {
	        			$partner['client']='+'.$partner['client'];
	        		}
	        		$data[]=array(
	        			'SendClientAddress',
	        			$partner['client']
	        		);
            	}
        	}
        	elseif($p[0]=='set_tlv' && $p[1]==1008 && $open===true) { // Добавление в чек покупателя
        		if(mb_strpos($p[3], '@')===false) {
        			$p[3]='+'.$p[3];
        		}
        		$data[]=array(
        			'SendClientAddress',
        			$p[3]
        		);
        	}
        	elseif($p[0]=='smde' && $open===true) { // Добавление товара в чек
        		$line=json_decode($p[1], true);
        		if(!$line['psr']) $line['psr']=4;
        		if(!$line['ppr']) $line['ppr']=1;
        		if(!isset($line['units'])) $line['units']=255;
        		$line['price']/=100;
        		$line['quantity']/=1000;

        		$data[]=array(
        			'SetItemTaxes',
        			$line['vat']-1
        		);

        		if($this->sets['version']=='1.2' || $this->sets['version']=='1.1') {
        			$data[]=array(
	                	'SetTagAttribute',
	                	2108,
	                	(int) $line['units']
	                );

	                if(isset($line['country_id']) && $line['country_id']!='000') {
				        $data[]=array(
		                	'SetTagAttribute',
		                	1230,
		                	$line['country_id']
		                );

		                $data[]=array(
		                	'SetTagAttribute',
		                	1231,
		                	$line['gtd']
		                );
				    }

	        		// Маркировка
	                if($line['mark']!='' && !$correct && (int)$line['egais']!=1) {
	                	$mark=str_replace('{{U+003B}}', ';', $line['mark']);
	                    $clearmark=true;
	                    $data[]=array(
	                    	'SetTagAttribute',
	                    	1163,
	                    	$mark
	                    );
	                }
	                /*if(!$line['mark'] && $line['barcode']) {
	                	$data[]=array(
	                    	'SetTagAttribute',
	                    	1163,
	                    	$line['barcode']
	                    );
	                }*/

	                $data[]=array(
	                	'SetTagAttribute',
	                	1214,
	                	(string) $line['psr']
	                );

	                $data[]=array(
	                	'SetTagAttribute',
	                	1212,
	                	(string) $line['ppr']
	                );

	                if($line['reqId']!='' && $line['reqTimestamp']>0) {
	                	if($line['inst']!='' && $line['version']!='') {
	                		$data[]=array(
		                		'SetSTLVTagAttribute',
								1260,
								array(1262, 1263, 1264, 1265),
								array('030', '2023-11-23T12:00:00.000Z', '1944', 'UUID='.$line['reqId'].'&Time='.$line['reqTimestamp'].'&Inst='.$line['inst'].'&Ver='.$line['version'])
		                	);
	                	}
	                	else {
							$data[]=array(
		                		'SetSTLVTagAttribute',
								1260,
								array(1262, 1263, 1264, 1265),
								array('030', '2023-11-23T12:00:00.000Z', '1944', 'UUID='.$line['reqId'].'&Time='.$line['reqTimestamp'])
		                	);
		                }
        			}

	                if($line['partner']) {
	                	if(!isset($line['partner']['type'])) $line['partner']['type']=5;
	                	$data[]=array(
	                		'SetTagAttribute',
	                		1222,
	                		pow(2, $line['partner']['type'])
	                	);
	                	if(mb_strlen($line['partner']['inn'])>=10) {
							$data[]=array(
		                		'SetTagAttribute',
		                		1226,
		                		$line['partner']['inn']
		                	);
				        }

				        if(mb_strlen($line['partner']['phone'])>=10) {
							$data[]=array(
		                		'SetTagAttribute',
		                		1171,
		                		'+'.$line['partner']['phone']
		                	);
				        }
				        if(mb_strlen($line['partner']['name'])) {
							$data[]=array(
		                		'SetTagAttribute',
		                		1225,
		                		$line['partner']['name']
		                	);
				        }
	            	}
	            }

        		$data[]=array(
        			'PrintRecItem',
        			number_format($line['quantity'], 3, '.', ''),
        			number_format($line['price'], 2, '.', ''),
        			$line['title'],
        			' '
        		);
        	}
        	elseif($p[0]=='tmde' && $open===true) { // Оплата чека
        		if($correct_data[1]>=0) {
        			$data[]=$correct_data;
        		}
        		$data[]=array(
        			'PrintRecTotal'
        		);
        		if(count($p)==3) { // передан 1 способ оплаты ФФД 1.05
        			$data[]=array(
        				'PrintRecItemPay',
        				$p[2],
        				number_format($p[1]/100, 2, '.', ''),
        				$this->pay_type[$p[2]]
        			);
        			if($p[2]==0 && $p[2]>$ticket_sum) {
        				$data[]=array(
        					'PrintRecItemPay',
        					0,
        					number_format(-($p[1]-$ticket_sum)/100, 2, '.', ''),
        					'Сдача'
        				);
        			}
        		}
        		else { // Несколько способов оплаты
        			foreach ($data as $data_n => $data_value) {
        				if($data_value[0]=='SetTaxationUsing') {
        					$data[$data_n][1]=$this->sno[$p[count($p)-1]];
        				}
        			}
        			if(count($p)==7) $end=4;
        			else $end=5;
        			for($j=0; $j<$end; $j++) {
        				if(isset($this->pay_type[$j]) && $p[$j+1]>0) {
        					$data[]=array(
	        					'PrintRecItemPay',
        						(string)$j,
        						number_format($p[$j+1]/100, 2, '.', ''),
        						$this->pay_type[$j]
        					);
        					if($j==0 && $p[$j+1]>$ticket_sum) {
		        				$data[]=array(
		        					'PrintRecItemPay',
		        					0,
		        					number_format(-($p[$j+1]-$ticket_sum)/100, 2, '.', ''),
		        					'Сдача'
		        				);
		        			}
        				}
        			}
        		}
        		$data[]=array(
        			'PrintLine',
        			0,
        			' '
        		);

        		$data[]=array(
        			'PrintLine',
        			0,
        			'Итого оплачено'
        		);
        	}
        	elseif($p[0]=='check_mark') {
        		if(!isset($p[3])) {
        			$p[3]=255;
        		}
        		$data[]=array(
        			'SendMarkupCodeFnCheck',
        			str_replace('{{U+003B}}', ';', $p[1]),
        			0,
        			(int)mb_strpos($p[1], '91'),
        			(int)mb_strpos($p[1], '92')
        		);
        		if(!$p[2]) {
        			$p[2]=1;
        		}
        		$data[]=array(
        			'SendMarkupCodeOismCheck',
        			0,
        			$p[3]==0?1:2,
        			number_format($p[2], 2, '.', ''),
        			$p[3],
        			'',
        			''
        		);
        		$data[]=array(
        			'GetMarkupCodeOismResult'
        		);
        		$data[]=array(
        			'SaveMarkupCodeCheckResult',
        			true
        		);
        	}
        	elseif($p[0]=='correction') {
        		$correct_data=json_decode($p[1], true);
        		if($correct_data['user_name']) {
        			$data[]=array(
        				'SetUserName',
        				$correct_data['user_name']
        			);
        		}

        		$data[]=array(
        			'SetTaxationUsing',
        			$this->sno[$correct_data['sno']]
        		);
        		$data[]=array(
        			'OpenRec',
        			19
        		);
        		$data[]=array(
        			'FNMakeCorrectionRec',
        			(int)$correct_data['operation'],
        			$correct_data['psr']=='cash'?$correct_data['sum']:0,
        			$correct_data['psr']=='emoney'?$correct_data['sum']:0,
        			0,
        			0,
        			0,
        			$correct_data['taxNum'],
        			$correct_data['corrType'],
        			$correct_data['description'],
        			date('Y-m-d', strtotime($correct_data['docDate'])).'T00:00:00',
        			$correct_data['docNum'],
        		);
        		$data[]=array(
        			'CloseRec'
        		);
        	}
        }
        if($open) {
        	$open=false;
        	$ticket_sum=0;
        	$data[]=array(
        		'CloseRec'
        	);
        	if($open_type!=9) {
	        	$data[]=array(
	        		'FNGetLastFDNum'
	        	);
	        	$data[]=array(
	        		'FNGetLastFiscalSign'
	        	);
	        	$data[]=array(
	        		'FNGetLastDocDateTime'
	        	);
	        }
        }

        if($clearmark) {
        	$data[]=array(
        		'ClearAllMarkupCodeCheckResult'
        	);
        }
        return $data;
	}

	function get_paper_width() {
    	return $this->config['PaperWidth'];
    }
}
