<?php
namespace Models;

class php_neva_ffd105_Fr_php {
	public $f3, $sets, $config, $web;
    public $fd=0; // Номер ФД
    public $fp=0; // Фискальный признак
    public $kkm_time=0; // Время чека
    public $ticket=false;
    public $header=false;
    public $footer=false;
    public $ticket_types=array(
        0=>array('type'=>1, 'value'=>1),
        1=>array('type'=>2, 'value'=>2),
        128=>array('type'=>7, 'value'=>2),
        130=>array('type'=>9, 'value'=>1),
    );
    public $paymethods=array(
        0=>array('type'=>1, 'tag'=>1031),
        1=>array('type'=>2, 'tag'=>1081),
        2=>array('type'=>3, 'tag'=>1215),
        3=>array('type'=>4, 'tag'=>1216),
        4=>array('type'=>5, 'tag'=>1217),
    );
    public $sno=array(
        '01'=>1, // Общая
        '02'=>2, // Упрощённая (Доход)
        '04'=>4, // Упрощённая (Доход минус Расход)
        '08'=>8, // Единый налог на вменённый доход
        '10'=>16, // Единый сельскохозяйственный налог
        '20'=>32 // Патентная система налогообложения
    );
	
	function __construct($f3, $sets, $config) {
		$this->f3=$f3;
		$this->sets=$sets;
        if(!$config['UserLogin']) $config['UserLogin']=99;
        if(!$config['UserPass']) $config['UserPass']=99;
        if(mb_substr($this->sets['url'], -1)=='/') {
            $this->sets['url']=mb_substr($this->sets['url'], 0, -1);
        }
        $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($config['vat_type'][$type])) {
                $config['vat_type'][$type]=$vat;
            }
        }
        $this->config=$config;
        $this->web=\Web::instance();
	}

    function send_command($url, $options) {
        $options['header'][]='Authorization: Basic '.base64_encode($this->config['UserLogin'].':'.$this->config['UserPass']);
        $options['header'][]='Content-Type: application/json';
        $options['header'][]='Expect:';
        $url=$this->sets['url'].$url;
        $res=$this->web->request($url, $options);
        $json=json_decode($res['body'], true);
        if(mb_strpos($res['headers'][0], '200')>0) {
            if(!$json) {
                $json=array(
                    'result'=>0,
                    'body'=>$res['body']
                );
            }
            if(isset($json['document']['result'])) {
                $json['result']=$json['document']['result'];
            }
            return $json;
        }
        else {
            if($this->errors[$json['document']['result']]) {
                $error_txt=$this->errors[$json['result']];
            }
            elseif($json['document']['message']['resultDescription']) {
                $error_txt=$json['document']['message']['resultDescription'];
            }
            else {
                $error_txt='Не удалось отправить команду: '.$url;
            }
            $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 $error_txt;
            exit();
        }
    }

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

    // Протяжка
    function feed($data) {
        $str[1]=str_repeat("#kkm_br#", $data[1]);
        return $this->p($str);
    }

    // Открыть смену
    function open_session($data) {
        $url='/cycleopen.json?print='.(isset($data[1])?$data[1]:1);
        $vars=array(
            'document'=>array(
                'sessionId'=>microtime(true),
                'print'=>isset($data[1])?$data[1]:1,
                'data'=>array(
                    'fiscprops'=>array()
                )
            )
        );
        $cashier=explode('{{user_inn}}', $data[2]);
        if($cashier[0]) {
            $vars['document']['data']['fiscprops'][]=array(
                'tag'=>1021,
                'value'=>$cashier[0]
            );
        }
        if($cashier[1] && mb_strlen($cashier[1])==12) {
            $vars['document']['data']['fiscprops'][]=array(
                'tag'=>1203,
                'value'=>$cashier[1]
            );
        }

        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        return $this->send_command($url, $options);
    }

    // Закрыть смену
    function z($data) {
        $url='/cycleclose.json';
        $vars=array(
            'document'=>array(
                'sessionId'=>microtime(true),
                'print'=>isset($data[1])?$data[1]:1,
                'data'=>array(
                    'fiscprops'=>array(
                        array()
                    )
                )
            )
        );
        $cashier=explode('{{user_inn}}', $data[2]);
        if($cashier[0]) {
            $vars['document']['data']['fiscprops'][]=array(
                'tag'=>1021,
                'value'=>$cashier[0]
            );
        }
        if($cashier[1] && mb_strlen($cashier[1])==12) {
            $vars['document']['data']['fiscprops'][]=array(
                'tag'=>1203,
                'value'=>$cashier[1]
            );
        }
        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        return $this->send_command($url, $options);
    }

    // Печать QR
    function qr($data) {
        $url='/printtext.json';
        $vars=array(
            'document'=>array(
                'sessionId'=>microtime(true),
                'print'=>1,
                'data'=>array(
                    'lines'=>array(
                        array(
                            'tag'=>3006,
                            'value'=>$data[1]
                        )
                    )
                )
            )
        );
        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        return $this->send_command($url, $options);
    }

    // Печать штрих-кода
    function barcode($data) {
        $data[1]='[barcode]'.$data[1].'[/barcode]';
        return $this->p($data);
    }

    // Форматирование текста
    function text_format($s) {
        if(mb_strpos($s, '#kkm_bold#')!==false) {
            $s=str_replace('#kkm_bold#', '[b]', $s).'[/b]';
        }
        if(mb_strpos($s, '#kkm_right#')!==false) {
            $s=str_replace("#kkm_right#", '[right]', $s).'[/right]';
        }
        elseif(mb_strpos($s, '#kkm_center#')!==false) {
            $s=str_replace("#kkm_center#", '[center]', $s).'[/center]';
        }
        else {
            $s='[left]'.$s.'[/left]';
        }
        return $s;
    }

    // Печать текста
    function p($data) {
        if(!isset($data[1])) $data[1]=' ';
        $txts=explode('#kkm_br#',$data[1]);
        $txt='';
        foreach ($txts as $n=>$t) {
            if(!$t)$t=' ';
            $txt.=$this->text_format($t)."\n";
        }
        $url='/printrichtext.json';
        $vars=array(
            'document'=>array(
                'bbcode'=>base64_encode($txt),
                'version'=>'1.0',
                'protocol'=>'1'
            )
        );
        //var_dump($txt); exit();
        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        return $this->send_command($url, $options);
    }

    function pm($data) {
        if(!isset($data[2])) $data[2]=' ';
        $txts=explode('#kkm_br#',$data[2]);
        $txt='';
        foreach ($txts as $n=>$t) {
            if(!$t)$t=' ';
            $t=$this->text_format($t)."\n";
            if(!$t) continue;
            if($data[1]>0) {
                $str=mb_str_split($t, $data[1]);
            }
            else {
                $str=array($t);
            }
            foreach($str as $s) {
                if(!$s) $s=' ';
                $txt.=$s."\n";
            }
        }
        $url='/printrichtext.json';
        $vars=array(
            'document'=>array(
                'bbcode'=>base64_encode($txt),
                'version'=>'1.0',
                'protocol'=>'1'
            )
        );
        //var_dump($txt); exit();
        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        return $this->send_command($url, $options);
    }

    function print_font($data) {
        $size=array(
            1=>'small',
            2=>'normal',
            3=>'middle',
            4=>'large'
        );
        $data[2]='[size='.($size[$data[1]]?$size[$data[1]]:'normal').']'.$data[2].'[/size]';
        return $this->p(array('p', $data[2]));
    }

    function print_bold($data) {
        $data[1]='[b]'.$data[1].'[/b]';
        return $this->p($data);
    }

    // X отчет
    function x($data) {
        $url='/xreport.json?print=1';
        $options=array(
            'method'=>'GET'
        );
        return $this->send_command($url, $options);
    }

    // Статус ККМ
    function d($data) {
        $url='/cashboxstatus.json';
        $options=array(
            'method'=>'GET'
        );
        $res=$this->send_command($url, $options);
        if($res['result']!=0) {
            return $res;
        }
        $allkeys=array(
            'agentFlags'=>'Признак агента',
            'allowGames'=>'Признак проведения азартных игр',
            'allowLotteries'=>'Признак проведения лотереи',
            'allowServices'=>'Признак расчетов за услуги',
            'atmNumber'=>'Номер автомата',
            'automatMode'=>'Признак автоматического режима',
            'cash'=>'Наличность в кассе (в копейках)',
            'cashBoxNumber'=>'Номер ккм в зале',
            'cycleClosed'=>'Дата закрытия смены',
            'cashier'=>'Номер кассира',
            'cycleNumber'=>'Номер смены (текущей или следующей, если закрыта)',
            'cycleOpened'=>'Дата открытия смены',
            'dt'=>'Дата/время в кассе',
            'email'=>'Адрес электронной почты отправителя чека',
            'excisableGoods'=>'Продажа подакцизного товара',
            'externPrinter'=>'Признак установки принтера в автомате',
            'fSfDfVersion'=>'Версия ФФД ФН',
            'fdfVersion'=>'Версия ФФД ККТ',
            'flags'=>'Флаги состояния ККМ',
            'fnsSite'=>'Адрес сайта ФНС',
            'fsNumber'=>'Номер ФН',
            'fsStatus'=>array(
                'title'=>'Состояние фискального накопителя',
                'data'=>array(
                    'cycleIsOpen'=>'Флаг открытия смены',
                    'debugMode'=>'Отладочная версия ФН',
                    'fsNumber'=>'Номер фискального накопителя',
                    'fsVersion'=>'Версия фискального накопителя',
                    'lastDocDt'=>'Дата последнего документа',
                    'lastDocNumber'=>'Номер последнего документа',
                    'lifeTime'=>array(
                        'title'=>'Данные о перерегистрациях',
                        'data'=>array(
                            'availableRegistrations'=>'Доступно перерегистраций',
                            'completedRegistrations'=>'Выполнено перерегистраций',
                            'expirationDt'=>'Дата окончания срока использования фн'
                        )
                    ),
                    'phase'=>'Фаза жизни ФН',
                    'transport'=>array(
                        'title'=>'Состояние обмена с ОФД',
                        'data'=>array(
                            'firstDocDt'=>'Дата первого неотправленного документа',
                            'firstDocNumber'=>'Номер первого неотправленного документа',
                            'offlineDocsCount'=>'Количество неотправленных документов',
                            'state'=>'Состояние обмена с ОФД'
                        )
                    )
                )
            ),
            'internetOnly'=>'Признак ККТ для расчетов только в Интернет',
            'introductions'=>'Количество внесений',
            'introductionsSum'=>'Сумма внесений (в копейках)',
            'lastCheckNumber'=>'Номер последнего фискального документа',
            'makeBso'=>'Признак АС БСО',
            'model'=>'Модель кассы',
            'modelstr'=>'Модель кассы/фр',
            'ofdInn'=>'ИНН ОФД',
            'ofdName'=>'Наименование ОФД',
            'offlineMode'=>'Признак автономного режима',
            'paymentAddress'=>'Адрес расчетов',
            'paymentPlace'=>'Место расчетов',
            'payouts'=>'Количество выплат',
            'payoutsSum'=>'Сумма выплат (в копейках)',
            'ipAddresses'=>'IP адрес',
            'regCashierInn'=>'ИНН кассира',
            'regCashierName'=>'Кассир',
            'regDate'=>'Дата фискализации',
            'regDocNumber'=>'Номер документа фискализации',
            'regNumber'=>'Регистрационный номер ККМ',
            'serial'=>'Заводской номер ККМ',
            'shortFlags'=>'Короткое состояние ККМ',
            'taxes'=>'Системы налогообложения',
            'useEncryption'=>'Признак шифрования',
            'userInn'=>'ИНН пользователя',
            'userName'=>'Наименование пользователя',
        );
        function checkv($v) {
            if(is_bool($v)) {
                if($v==true) {
                    $v='true';
                }
                else {
                    $v='false';
                }
            }
            if($v==null) {
                $v='NULL';
            }
            return $v;
        }
        function print_value($data, $keys) {
            $flags=array(
                0=>array(
                    'title'=>'ККТ фискализирована: ',
                    'data'=>array(
                        0=>'нет',
                        1=>'да'
                    )
                ),
                1=>array(
                    'title'=>'Смена открыта: ',
                    'data'=>array(
                        0=>'нет',
                        1=>'да'
                    )
                ),
                2=>array(
                    'title'=>'Состояние денежного ящика: ',
                    'data'=>array(
                        0=>'открыт',
                        1=>'закрыт'
                    )
                ),
                3=>array(
                    'title'=>'Датчик ЧЛ: ',
                    'data'=>array(
                        0=>'нет бумаги',
                        1=>'есть бумага'
                    )
                ),
                5=>array(
                    'title'=>'Состояние датчика крышки: ',
                    'data'=>array(
                        0=>'крышка закрыта',
                        1=>'крышка открыта'
                    )
                ),
                6=>array(
                    'title'=>'Состояние ФН: ',
                    'data'=>array(
                        0=>'не активизирован',
                        1=>'активизирован'
                    )
                ),
                7=>array(
                    'title'=>'Батарейка ',
                    'data'=>array(
                        0=>'не установлена',
                        1=>'установлена'
                    )
                ),
            );
            $phase=array(
                1=>'Готовность к фискализации',
                2=>'Фискальный режим',
                3=>'Постфискальный режим (передача фискальных документов в ОФД)',
                4=>'Доступ к Архиву ФН'
            );
            $state=array(
                0=>'Транспортное соединение установлено',
                1=>'Есть сообщение для передачи в ОФД',
                2=>'Ожидание ответного сообщения (квитанции) от ОФД',
                3=>'Есть команда от ОФД',
                4=>'Изменились настройки соединения с ОФД',
                5=>'Ожидание ответа на команду от ОФД'
            );
            $taxes=array(
                1=>'Общая',
                2=>'Упрощённая (Доход)',
                4=>'Упрощённая (Доход минус Расход)',
                8=>'Единый налог на вменённый доход',
                16=>'Единый сельскохозяйственный налог',
                32=>'Патентная система налогообложения'
            );
            foreach($data as $k=>$v) {
                if(!isset($keys[$k]) || $keys[$k]=='') {
                    continue;
                }
                if($k=='flags') {
                    echo '<p align="center"><b>'.$keys[$k].'</b></p>';
                    $v=decbin($v);
                    for($i=0; $i<mb_strlen($v); $i++) {
                        $b=mb_substr($v, $i, 1);
                        if($flags[$i]) {
                            echo '<p><b>'.$flags[$i]['title'].'</b> '.$flags[$i]['data'][$b].'</p>';
                        }
                    }
                    echo '<br>';
                }
                elseif($k=='phase') {
                    echo '<p><b>'.$keys[$k].'</b>: '.$phase[$v].'</p>';
                }
                elseif($k=='taxes') {
                    echo '<p><b>'.$keys[$k].'</b>: '.$taxes[$v].'</p>';
                }
                elseif($k=='state'){
                    echo '<p align="center"><b>'.$keys[$k].'</b></p>';
                    $v=decbin($v);
                    for($i=0; $i<mb_strlen($v); $i++) {
                        $b=mb_substr($v, $i, 1);
                        if($state[$i]) {
                            echo '<p><b>'.$state[$i].'</b>: '.($b==1?'да':'нет').'</p>';
                        }
                    }
                    echo '<br>';
                }
                elseif(!is_array($v) && !is_array($keys[$k])) {
                    echo '<p><b>'.$keys[$k].'</b>: '.checkv($v).'</p>';
                }
                elseif($v && is_array($keys[$k])) {
                    echo '<p align="center"><b>'.$keys[$k]['title'].'</b></p>';
                    print_value($v, $keys[$k]['data']);
                }
                else {
                    //echo '<p align="center"><b>'.$keys[$k].'</b></p>';
                    foreach ($v as $vk => $vv) {
                        echo'<p><b>'.$vk.'</b>: '.checkv($vv).'</p>';
                    }
                }
            }
            echo '<br>';
        }
        print_value($res['cashboxStatus'], $allkeys, $flags);
        exit();
    }

    // Внесение или изъятие из кассы
    function imde($data) {
        if($data[1]>0) {
            $url='/introduction.json';
        }
        else {
            $url='/payout.json';
        }
        $url.='?sum='.abs($data[1]);
        $options=array(
            'method'=>'GET'
        );
        return $this->send_command($url, $options);
    }

    // Открытие чека
    function b($data) {
        $url='/fiscalcheck.json';
        $this->ticket=array(
            'url'=>$url,
            'method'=>'POST',
            'document'=>array(
                'sessionId'=>microtime(true),
                'print'=>$data[3],
                'data'=>array(
                    'sum'=>0,
                    'moneyType'=>1,
                    'type'=>$this->ticket_types[$data[1]]['type'],
                    'fiscprops'=>array(
                        array(
                            'tag'=>1055,
                            'value'=>$this->sno[$this->sets['sno']]
                        ),
                        array(
                            'tag'=>1054,
                            'value'=>$this->ticket_types[$data[1]]['value']
                        )
                    )
                ),
                //'tax'=>(int)$this->sno[$this->sets['sno']]
            )
        );
        $cashier=explode('{{user_inn}}', $data[2]);
        if($cashier[0]) {
            $this->ticket['document']['data']['fiscprops'][]=array(
                'tag'=>1021,
                'value'=>$cashier[0]
            );
        }
        if($cashier[1] && mb_strlen($cashier[1])==12) {
            $this->ticket['document']['data']['fiscprops'][]=array(
                'tag'=>1203,
                'value'=>$cashier[1]
            );
        }

        $res['result']=0;
        return $res;
    }

    function partner($data) {
        if(is_array($this->ticket)) {
            $partner=json_decode($data[1], true);
            if($partner['client']) {
               if(is_numeric($partner['client']) && mb_strlen($partner['client'])==11) {
                    $partner['client']='+'.$partner['client'];
                }
                $this->ticket['document']['data']['fiscprops'][]=array(
                    'tag'=>1008,
                    'value'=>$partner['client']
                );
            }
            $res['result']=0;
        }
        else {
            $res['result']=1;
            $res['description']='Чек не открыт';
            $this->f3->get('logs_model')->save_log($res['description'].' (Касса)', 'error');
        }
    }

    function set_tlv($data) {
        if($data[1]==1008) {
            if(is_array($this->ticket)) {
                if(is_numeric($data[3]) && mb_strlen($data[3])==11) {
                    $data[3]='+'.$data[3];
                }
                $this->ticket['document']['data']['fiscprops'][]=array(
                    'tag'=>$data[1],
                    'value'=>$data[3]
                );
                $res['result']=0;
            }
            else {
                $res['result']=1;
                $res['message']['resultDescription']='Чек не открыт';
                $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
            }
        }
        elseif($data[1]==1173) {
            if(is_array($this->ticket)) {
                $data[3]=((int)$data[3]==0?1:0);
                $this->ticket['document']['data']['fiscprops'][]=array(
                    'tag'=>$data[1],
                    'value'=>$data[3]
                );
                $this->f3->set('COOKIE.correction_isIndependent', $data[3]);
                $res['result']=0;
            }
            else {
                $res['result']=1;
                $res['message']['resultDescription']='Чек не открыт';
                $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
            }
        }
        elseif($data[1]==1178) {
            if(is_array($this->ticket)) {
                $data[3]=date('Y-m-d', $data[3]);
                $this->ticket['document']['data']['fiscprops'][]=array(
                    'tag'=>$data[1],
                    'value'=>$data[3]
                );
                $this->ticket['document']['correctionReason']['date']=$data[3];
                $this->f3->set('COOKIE.correction_date', $data[3]);
                $res['result']=0;
            }
            else {
                $res['result']=1;
                $res['message']['resultDescription']='Чек не открыт';
                $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
            }
        }
        elseif($data[1]==1179) {
            if(is_array($this->ticket)) {
                $this->ticket['document']['data']['fiscprops'][]=array(
                    'tag'=>$data[1],
                    'value'=>$data[3]
                );
                $this->f3->set('COOKIE.correction_docNumber', $data[3]);
                $res['result']=0;
            }
            else {
                $res['result']=1;
                $res['message']['resultDescription']='Чек не открыт';
                $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
            }
        }
        else {
            $res['result']=1;
            $res['message']['resultDescription']='Команда неизвестна';
            $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
        }
        return  $res;
    }

    // Обработка кода маркировки
    function mark($mark) {
        $mlen=mb_strlen($mark);
        if($mlen!=8
            && $mlen!=13
            && $mlen!=14
            && preg_match("/[A-Za-z0-9\/\\!”%&’()*+-.,:;=<>?]/", $mark)
            && mb_substr($mark, 0, 2)=='01'
            && mb_substr($mark, 16, 2)=='21') {
            $mark=str_replace('\\u001d', '', $mark);
            $mark=str_replace('', '', $mark);
            $mark=mb_substr($mark, 0, 37);
        }
        return $mark;
    }

    // Добавление товара в чек
    function smde($data) {
        if(is_array($this->ticket)) {
            $line=json_decode($data[1], true);
            if(!$line['psr']) $line['psr']=4;
            if(!$line['ppr']) $line['ppr']=1;
            if(!isset($line['units'])) $line['units']=255;
            
            $line['line']=str_replace('{{U+003B}}', ';', $line['title']);
            $item=array(
                'tag'=>1059,
                'fiscprops'=>array(
                    array(
                        'tag'=>1214,
                        'value'=>$line['psr']
                    ),
                    array(
                        'tag'=>1212,
                        'value'=>$line['ppr']
                    ),
                    array(
                        'tag'=>1030,
                        'value'=>$line['title']
                    ),
                    array(
                        'tag'=>1079,
                        'value'=>(int)$line['price']
                    ),
                    array(
                        'tag'=>1023,
                        'value'=>number_format($line['quantity']/1000, 3, '.', '')
                    ),
                    array(
                        'tag'=>1199,
                        'value'=>(int)$line['vat']
                    )
                )
            );

            /*if(isset($p_name[1]) && $p_name[1]!='') {
                $res=$this->check_mark($p_name);
                $item['productCode']=array(
                    'type'=>'1300',
                    'data'=>$this->mark($p_name[1]),
                    'labelCheckResult'=>$res['results']
                );
                $this->ticket['document']['labledOperations'][]=$item;
            }
            else {
                $this->ticket['document']['operations'][]=$item;
            }*/
            $this->ticket['document']['data']['fiscprops'][]=$item;
            $res['result']=0;
        }
        else {
            $res['result']=1;
            $res['message']['resultDescription']='Чек не открыт';
            $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
        }
        return  $res;
    }

    // Оплата чека
    function tmde($data) {
        if(!is_array($this->ticket)) {
            $res['result']=1;
            $res['message']['resultDescription']='Чек не открыт';
            $this->f3->get('logs_model')->save_log($res['message']['resultDescription'].' (Касса)', 'error');
            return $res;
        }
        if(count($data)==3) {
            $this->ticket['document']['moneyType']=[$this->paymethods[$data[2]]['type']];
        }
        else {
            if(count($data)==7) $end=4;
            else $end=5;
            for($j=0; $j<$end; $j++) {
                if($j==0 || $data[$j+1]>0) {
                    $this->ticket['document']['data']['fiscprops'][]=array(
                        'tag'=>$this->paymethods[$j]['tag'],
                        'value'=>$data[$j+1]
                    );
                }
            }
        }
        $url=$this->ticket['url'];
        $this->ticket['document']['data']['fiscprops'][0]['value']=$this->sno[$data[count($data)-1]];
        //$this->ticket['document']['data']['fiscprops'][0]['value']=32;
        if($this->ticket['document']['type']==7 || $this->ticket['document']['type']==9) {
            /*if(!isset($this->ticket['document']['correctionReason'])) {
                $this->ticket['document']['correctionReason']=array(
                    'isIndependent'=>$this->f3->get('SESSION.correction_isIndependent'),
                    'date'=>$this->f3->get('SESSION.correction_date'),
                    'docNumber'=>$this->f3->get('SESSION.correction_docNumber'),
                );
                $this->clear_session=true;
                if(!$this->ticket['document']['correctionReason']['docNumber']);
            }
            if(!$this->ticket['document']['correctionReason']['docNumber'])$this->ticket['document']['correctionReason']['docNumber']=0;*/
        }
        $json=json_encode(array('document'=>$this->ticket['document']));
            //'content'=>'{"document":{"sessionId":"11111111);
        $options=array(
            'method'=>$this->ticket['method'],
            'content'=>$json
        );
        $this->ticket=false;
        return $this->send_command($url, $options);
    }

    // Аннулирование открытого чека
    function g($data) {
        return array('result'=>0);
    }

    // открыть денежный ящик
    function open_cash_box($data) {
        return array('result'=>0);
    }

    // Продолжить печать чека
    function continue_print($data) {
        $url='/reprintlastcheck.json';
        $options=array(
            'method'=>'GET'
        );
        return $this->send_command($url, $options);
    }

    function check_mark($data) {
        $url='/labelcheck.json';
        $vars=array(
            'document'=>array(
                'checkFlags'=>0,
                'excpectedStatus'=>1,
                'quantity'=>1,
                'rawLabel'=>$data[1]
            )
        );
        $options=array(
            'method'=>'POST',
            'content'=>json_encode($vars)
        );
        $res=$this->send_command($url, $options);
        if($res['result']>0) {
            return $res;
        }
        $errors=array(
            'st2109'=>array(
                2=>'Планируемый статус товара некорректен',
                3=>'Оборот товара приостановлен'
            ),
            'reqCode2105'=>array(
                1=>'Запрос имеет некорректный формат',
                2=>'Указанный в запросе код маркировки имеет некорректный формат (не распознан)'
            ),
            'reqResult'=>array(
                0=>'Результат проверки КП КМ отрицательный',
                2=>'Статус товара некорректен'
            )
        );
        $res['results']=$res;
        $reqResult=(string)base_convert($res['document']['reqResult'], 16, 2);
        if($res['document']['st2109']>1) {//} || $res['document']['reqCode2105']>0 || (int)mb_substr($reqResult, 0, 1)==0 || (int)mb_substr($reqResult, 2, 1)==0) {
            $res['check_mark']=false;
            $res['message']['resultDescription']=$errors['st2109'][$res['document']['st2109']];
            $res['result']=1;
        }
        if($res['document']['reqCode2105']>0) {//(int)mb_substr($reqResult, 0, 1)==0 || (int)mb_substr($reqResult, 2, 1)==0) {
            if(!$res['check_mark']) $res['message']['resultDescription'].='; ';
            $res['message']['resultDescription'].=$errors['reqCode2105'][$res['document']['reqCode2105']];
            $res['check_mark']=false;
            $res['result']=1;
        }
        $reqResult_0=(int)mb_substr($reqResult, 0, 1);
        $reqResult_2=(int)mb_substr($reqResult, 2, 1);
        if($reqResult_0==0) {
            if(!$res['check_mark']) $res['message']['resultDescription'].='; ';
            $res['message']['resultDescription'].=$errors['reqResult'][0];
            $res['check_mark']=false;
            $res['result']=1;
        }
        if($reqResult_2==0) {
            if(!$res['check_mark']) $res['message']['resultDescription'].='; ';
            $res['message']['resultDescription'].=$errors['reqResult'][2];
            $res['check_mark']=false;
            $res['result']=1;
        }
        return $res;
    }

    function preitem($data) {
        return array('result'=>0);
    }

    function preitem_end($data) {
        return array('result'=>0);
    }

    function postitem($data) {
        return array('result'=>0);
    }

    function postitem_end($data) {
        return array('result'=>0);
    }

    function printdoc($data) {
        return array('result'=>0);
    }

    function beep($data) {
        $this->print_font(array(1=>4, 2=>'Бип-Бип-БИИП'));
    }

	// Отправка запроса
	function send_ajax($strs, $timeout=3, $view=false) {
		/*if(!$this->f3->get('SESSION.'.$this->sets['printer'].'_drivers_init')) {
			$this->kkm_init();
		}*/

        $false=0;
		$str=explode("\n", $strs);
        foreach ($str as $s) {
            if($s=='') continue;
            $ss=explode(';', $s);
            $method=$ss[0];
            $n=count($ss);
            if($ss[$n-1]=='') {
                unset($ss[$n-1]);
            }
            if(method_exists($this, $method)) {
                $res=$this->$method($ss);
            }
            else {
                $error_txt='Неизвестная команда: '.$ss[0];
                $error_txt='<p class="false">'.$error_txt.'</p>';
                $this->f3->get('logs_model')->save_log($error_txt.' (Касса)', 'error');
                $false++;
                continue;
            }
            if($res['result']!=0) {
                $error_txt.='<p class="false">'.$res['document']['message']['resultDescription'].'</p>';
                $this->f3->get('logs_model')->save_log($res['document']['message']['resultDescription'].' (Касса)', 'error');
                $false++;
            }
            elseif($view) {
                echo '<p class="true">Команда выполнена успешно: '.$ss[0].'</p>';
            }

            if($res['document']['data']['fiscprops']) {
                $fiscprops=array_combine(array_column($res['document']['data']['fiscprops'], 'tag'), $res['document']['data']['fiscprops']);
                if($fiscprops[1040]['value']>0 && $fiscprops[1077]['value']) {
                    $this->fd=$fiscprops[1040]['value'];
                    $this->fp=$fiscprops[1077]['value'];
                    $this->kkm_time=$fiscprops[1012]['value'];
                    $this->f3->set('fn', $fiscprops[1041]['value']);
                }
            }
        }

        if($false>0 && !$view) {
            if($this->f3->get('fr_error_ignore')) {
                return array(
                    'success'=>false,
                    'error'=>$error_txt
                );
            }
            echo $error_txt;
            echo $continue_html= \Template::instance()->render('fr_error.htm');
            exit();
        }
        if((int)$res['result']==0) {
            $res['success']=true;
            if($this->clear_session==true) {
                $this->f3->clear('COOKIE.correction_isIndependent');
                $this->f3->clear('COOKIE.correction_date');
                $this->f3->clear('COOKIE.correction_docNumber');
            }
        }
        else {
            $res['success']=false;
        }
        if($this->fd!=0 && $this->fp!=0) {
            $res['fd']=$this->fd;
            $res['fp']=$this->fp;
            $res['kkm_time']=$this->kkm_time;
        }
        return $res;
	}

    // Проверить смену
    function change_status() {
        $url='/cashboxstatus.json';
        $options=array(
            'method'=>'GET'
        );
        $res=$this->send_command($url, $options);
        if($res['result']!=0) {
            return $res;
        }
        // closed - закрыта
        // opened - открыта
        // expired - истекла
        if($res['cashboxStatus']['fsStatus']['cycleIsOpen']!==1) {
            $status='closed';
        }
        elseif(strtotime($res['cashboxStatus']['cycleOpened'])+3600*24>time()) {
            $status='opened';
        }
        else {
            $status='expired';
        }
        return $status;
    }

    function check_fnstatus() {
        $url='/cashboxstatus.json';
        $options=array(
            'method'=>'GET'
        );
        $res=$this->send_command($url, $options);
        if($res['result']!=0) {
            return $res;
        }
        return array(
            'success'=>true,
            'kkm'=>'Нева',
            'ffd'=>$this->sets['version'],
            'inn'=>$res['cashboxStatus']['userInn'],
            'kpp'=>'',
            'org_name'=>$res['cashboxStatus']['userName'],
            'org_address'=>$res['cashboxStatus']['paymentAddress'],
            'ofd_n'=>$res['cashboxStatus']['fsStatus']['transport']['offlineDocsCount'],
            'fn_end'=>strtotime($res['cashboxStatus']['fsStatus']['lifeTime']['expirationDt'])
        );
    }

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

    public $errors=array(
        1=>'Контрольная лента обработана без ошибок',
        8=>'Неверная цена (сумма)',
        10=>'Неверное количество товара',
        11=>'Переполнение счетчика наличности',
        12=>'Невозможно сторно последней операции',
        13=>'Сторно по коду невозможно (в чеке зарегистрировано меньшее количество товаров с указанным кодом)',
        14=>'Невозможен повтор последней операции',
        15=>'Повторная скидка на операцию невозможна',
        16=>'Скидка/надбавка на предыдущую операцию невозможна',
        17=>'Неверный код товара',
        18=>'Неверный штрихкод товара',
        19=>'Неверный формат',
        20=>'Неверная длина',
        21=>'ККТ заблокирована в режиме ввода даты',
        22=>'Требуется подтверждение ввода даты',
        24=>'Нет больше данных для передачи ПО ККТ',
        25=>'Нет подтверждения или отмены продажи',
        26=>'Отчет с гашением прерван. Вход в режим невозможен.',
        27=>'Отключение контроля наличности невозможно (не настроены необходимые типы оплаты).',
        30=>'Вход в режим заблокирован',
        31=>'Проверьте дату и время',
        32=>'Дата и время в ККТ меньше чем в ФН',
        33=>'Невозможно закрыть архив',
        61=>'Товар не найден',
        62=>'Весовой штрихкод с количеством <> 1.000',
        63=>'Переполнение буфера чека',
        64=>'Недостаточное количество товара',
        65=>'Сторнируемое количество больше проданного',
        66=>'Заблокированный товар не найден в буфере чека',
        67=>'Данный товар не продавался в чеке, сторно невозможно',
        70=>'Неверная команда от ККТ',
        102=>'Команда не реализуется в данном режиме ККТ',
        103=>'Нет бумаги',
        104=>'Нет связи с принтером чеков',
        105=>'Механическая ошибка печатающего устройства',
        106=>'Неверный тип чека',
        107=>'Нет больше строк картинки/штрихкода',
        108=>'Неверный номер регистра',
        109=>'Недопустимое целевое устройство',
        110=>'Нет места в массиве картинок/штрихкодов',
        111=>'Неверный номер картинки/штрихкода (картинка/штрихкод отсутствует)',
        112=>'Сумма сторно больше, чем было получено данным типом оплаты',
        113=>'Сумма не наличных платежей превышает сумму чека',
        114=>'Сумма платежей меньше суммы чека',
        115=>'Накопление меньше суммы возврата или аннулирования',
        117=>'Переполнение суммы платежей',
        118=>'Предыдущая операция незавершена',
        119=>'Ошибка GSM-модуля',
        122=>'Данная модель ККТ не может выполнить команду',
        123=>'Неверная величина скидки / надбавки',
        124=>'Операция после скидки / надбавки невозможна',
        125=>'Неверная секция',
        126=>'Неверный вид оплаты',
        127=>'Переполнение при умножении',
        128=>'Операция запрещена в таблице настроек',
        129=>'Переполнение итога чека',
        130=>'Открыт чек аннулирования – операция невозможна',
        132=>'Переполнение буфера контрольной ленты',
        134=>'Вносимая клиентом сумма меньше суммы чека',
        135=>'Открыт чек возврата – операция невозможна',
        136=>'Смена превысила 24 часа',
        137=>'Открыт чек продажи – операция невозможна',
        138=>'Переполнение ФП',
        140=>'Неверный пароль',
        141=>'Буфер контрольной ленты не переполнен',
        142=>'Идет обработка контрольной ленты',
        143=>'Обнуленная касса (повторное гашение невозможно)',
        145=>'Неверный номер таблицы',
        146=>'Неверный номер ряда',
        147=>'Неверный номер поля',
        148=>'Неверная дата',
        149=>'Неверное время',
        150=>'Сумма чека по секции меньше суммы сторно',
        151=>'Подсчет суммы сдачи невозможен',
        152=>'В ККТ нет денег для выплаты',
        154=>'Чек закрыт – операция невозможна',
        155=>'Чек открыт – операция невозможна',
        156=>'Смена открыта, операция невозможна',
        158=>'Заводской номер уже задан',
        162=>'Неверный номер смены',
        163=>'Неверный тип отчета',
        164=>'Недопустимый пароль',
        165=>'Недопустимый заводской номер ККТ',
        166=>'Недопустимый РНМ',
        167=>'Недопустимый ИНН',
        168=>'ККТ не фискализирована',
        169=>'Не задан заводской номер',
        170=>'Нет отчетов',
        171=>'Режим не активизирован',
        172=>'Нет указанного чека в КЛ',
        173=>'Нет больше записей КЛ',
        174=>'Некорректный код или номер кода защиты ККТ',
        175=>'Отсутствуют данные в буфере ККТ',
        176=>'Требуется выполнение общего гашения',
        177=>'Команда не разрешена введенными кодами защиты ККТ',
        178=>'Невозможна отмена скидки/надбавки',
        179=>'Невозможно закрыть чек данным типом оплаты (в чеке присутствуют операции без контроля наличных)',
        180=>'Неверный номер маршрута',
        181=>'Неверный номер начальной зоны',
        182=>'Неверный номер конечной зоны',
        183=>'Неверный тип тарифа',
        184=>'Неверный тариф',
        186=>'Ошибка обмена с фискальным модулем',
        190=>'Необходимо провести профилактические работы',
        191=>'Неверные номера смен в ККТ и ФН',
        200=>'Нет устройства, обрабатывающего данную команду',
        201=>'Нет связи с внешним устройством',
        202=>'Ошибочное состояние ТРК',
        203=>'Больше одной регистрации в чеке',
        204=>'Ошибочный номер ТРК',
        205=>'Неверный делитель',
        208=>'Активизация данного ФН в составе данной ККТ невозможна',
        209=>'Перегрев головки принтера',
        210=>'Ошибка обмена с ФН на уровне интерфейса I2C',
        211=>'Ошибка формата передачи ФН',
        212=>'Неверное состояние ФН',
        213=>'Неисправимая ошибка ФН',
        214=>'Ошибка КС ФН',
        215=>'Закончен срок эксплуатации ФН',
        216=>'Архив ФН переполнен',
        217=>'В ФН переданы неверная дата или время',
        218=>'В ФН нет запрошенных данных',
        219=>'Переполнение ФН (итог чека)',
        220=>'Буфер переполнен',
        221=>'Невозможно напечатать вторую фискальную копию',
        222=>'Требуется гашение ЭЖ',
        223=>'Сумма налога больше суммы регистраций по чеку и/или итога или больше суммы регистрации',
        224=>'Начисление налога на последнюю операцию невозможно',
        225=>'Неверный номер ФН',
        228=>'Сумма сторно налога больше суммы зарегистрированного налога данного типа',
        229=>'Ошибка SD',
        230=>'Операция невозможна, недостаточно питания',
        231=>'Некорректное значение параметров команды ФН',
        232=>'Превышение размеров TLV данных ФН',
        233=>'Нет транспортного соединения ФН',
        234=>'Исчерпан ресурс КС ФН',
        235=>'Исчерпан ресурс хранения ФН',
        236=>'Сообщение от ОФД не может быть принято ФН',
        237=>'В ФН есть неотправленные ФД',
        241=>'Ошибочные флаги агента',
        242=>'Не хватает реквизитов',
        243=>'ККТ не на связи',
        244=>'Банковская ошибка',
    );
}
