<?php
namespace Models;

// модель для чеков
class Receipts extends \DB\SQL\Mapper {
	public $db, $f3, $fr, $egais, $printer;

	public function __construct($db, $f3, $printer='kkm', $fr=false) {
		parent::__construct($db, 'receipts'); // подключаемся к таблице чеков
		$this->db=$db;
		$this->f3=$f3;
		if($fr===false) {
			$this->fr=new \Models\Fr($db, $f3, $printer);
			if($printer!='kkm' && $this->fr->sets['active']!=1) {
				//$this->fr=new \Models\Fr($db, $f3, 'kkm');
			}
		}
		else {
			$this->fr=$fr;
		}
		$this->printer=$printer;
		$this->egais=new \Models\Egais($db, $f3);
		$this->f3->set('fr_settings', $this->fr->sets);
	}

	// Информация об открываемой странице
	function page_data($page='sales') {
		$pages=array(
			'sales'=>array(
				'title'=>'Продажа',
				'inc'=>'receipts_sales.htm'
			),
			'return'=>array(
				'title'=>'Возврат',
				'inc'=>'receipts_return.htm'
			),
			'pricetags'=>array(
				'title'=>'Печать ценников и готовых наборов',
				'inc'=>'receipts_sales.htm'
			),
			'writeoff'=>array(
				'title'=>'Списание',
				'inc'=>'receipts_sales.htm'
			),
			'select_barcode'=>array(
				'title'=>'Выбор штрих-кода',
				'inc'=>'receipts_select_barcode.htm'
			),
			'printpricetags'=>array(
				'title'=>'Печать ценников',
				'inc'=>'receipts_printpricetags.htm'
			),
			'correct_sales'=>array(
				'title'=>'Коррекция/Продажа',
				'inc'=>'receipts_sales.htm'
			),
			'correct_return'=>array(
				'title'=>'Коррекция/Возврат',
				'inc'=>'receipts_sales.htm'
			),
			'search'=>array(
				'title'=>'Поиск чеков',
				'inc'=>'receipts_search.htm'
			),
			'paymentmethods'=>array(
				'title'=>'Оплата чека',
				'inc'=>'receipts_paymentmethods.htm'
			),
			'show'=>array(
				'title'=>'Просмотр чека',
				'inc'=>'receipts_show.htm'
			),
			'change_price'=>array(
				'title'=>'Редактирование цены продажи',
				'inc'=>'receipts_change_price.htm'
			),
			'change_count'=>array(
				'title'=>'Изменение количества продажи',
				'inc'=>'receipts_change_count.htm'
			),
			'cashin'=>array(
				'title'=>'Внесение денег в кассу',
				'inc'=>'receipts_cashin.htm'
			),
			'cashout'=>array(
				'title'=>'Изъятие денег из кассы',
				'inc'=>'receipts_cashout.htm'
			),
			'reports'=>array(
				'title'=>'Смены и отчеты',
				'inc'=>'receipts_reports.htm'
			),
			'new'=>array(
				'title'=>'Открытие нового чека',
				'inc'=>'receipts_new.htm'
			),
			'switch'=>array(
				'title'=>'Переключение на другой чек',
				'inc'=>'receipts_switch.htm'
			),
			'all_open'=>array(
				'title'=>'Открытые чеки',
				'inc'=>'receipts_all_open.htm'
			),
			'move'=>array(
				'title'=>'Перемещение чека на другой стол',
				'inc'=>'receipts_move.htm'
			),
			'online_order'=>array(
				'title'=>'Поиск документов',
				'inc'=>'receipts_online_order.htm'
			),
			'online_order_result'=>array(
				'title'=>'Документы',
				'inc'=>'receipts_online_order_result.htm'
			),
			'show_online_order'=>array(
				'title'=>'Просмотр документа',
				'inc'=>'receipts_show_online_order.htm'
			),
			'print'=>array(
				'title'=>'Печать чека',
				'inc'=>'receipts_print.htm'
			),
			'walk'=>array(
				'title'=>'Отметить проход сотрудника',
				'inc'=>'receipts_walk.htm'
			),
			'walk_add_card'=>array(
				'title'=>'Отметить проход сотрудника',
				'inc'=>'receipts_walk_add_card.htm'
			),
			'add_marking'=>array(
				'title'=>'Укажите код маркировки товара',
				'inc'=>'receipts_add_marking.htm'
			),
			'marking_error'=>array(
				'title'=>'Ошибка проверки кода маркировки товара',
				'inc'=>'receipts_marking_error.htm'
			),
			'marking_invalid_error'=>array(
				'title'=>'Ошибка сканирования кода маркировки товара',
				'inc'=>'receipts_marking_invalid_error.htm'
			),
			'mrc_error'=>array(
				'title'=>'Ошибка проверки кода маркировки товара',
				'inc'=>'receipts_mrc_error.htm'
			),
			'marking_double_error'=>array(
				'title'=>'Ошибка проверки кода маркировки товара',
				'inc'=>'receipts_marking_double_error.htm'
			),
			'expiration_date_error'=>array(
				'title'=>'Ошибка проверки срока годности',
				'inc'=>'receipts_expiration_date_error.htm'
			),
			'current_volume_error'=>array(
				'title'=>'Ошибка кол-ва продажи',
				'inc'=>'receipts_current_volume_error.htm'
			),
			'egais_error'=>array(
				'title'=>'Ошибка проверки алкогольной продукции',
				'inc'=>'receipts_egais_error.htm'
			),
			'egais_error_2'=>array(
				'title'=>'Ошибка проверки алкогольной продукции',
				'inc'=>'receipts_egais_error_2.htm'
			),
			'egais_ticket_error'=>array(
				'title'=>'Ошибка создания чека в ЕГАИС',
				'inc'=>'receipts_egais_ticket_error.htm'
			),
			'chpok'=>array(
				'title'=>'Вскрытие тары',
				'inc'=>'receipts_chpok.htm'
			),
			'chpok_end'=>array(
				'title'=>'Вскрытие тары',
				'inc'=>'receipts_chpok_end.htm'
			),
			'chpok_egais_error'=>array(
				'title'=>'Ошибка проверки алкогольной продукции',
				'inc'=>'receipts_chpok_egais_error.htm'
			),
			'modifiers'=>array(
				'title'=>'Модификаторы',
				'inc'=>'receipts_modifiers.htm'
			),
			'correct1'=>array(
				'title'=>'Сформировать чек коррекции',
				'inc'=>'receipts_correct1.htm'
			),
			'turn'=>array(
				'title'=>'Очередность позиций',
				'inc'=>'receipts_turn.htm'
			),
			'print_turns'=>array(
				'title'=>'Выберите очередь',
				'inc'=>'receipts_print_turns.htm'
			),
			'executor_display'=>array(
				'title'=>'Заказы',
				'inc'=>'receipts_executor_display.htm'
			),
			'client_display'=>array(
				'title'=>'Заказы',
				'inc'=>'receipts_client_display.htm'
			),
			'archive'=>array(
				'title'=>'Архив заказов',
				'inc'=>'receipts_archive.htm'
			),
			'online_order_status'=>array(
				'title'=>'Установить статус заказа',
				'inc'=>'receipts_online_order_status.htm'
			),
			'show_qr'=>array(
				'title'=>'Сканируйте QR-код для оплаты',
				'inc'=>'receipts_show_qr.htm'
			),
			'success_pay'=>array(
				'title'=>'Заказ успешно оформлен',
				'inc'=>'receipts_success_pay.htm'
			),
			'add_combo'=>array(
				'title'=>'Добавить комбинацию',
				'inc'=>'receipts_add_combo.htm'
			),
			'split'=>array(
				'title'=>'Разделить чек',
				'inc'=>'receipts_split.htm'
			),
			'snoerror'=>array(
				'title'=>'Товары с разными СНО',
				'inc'=>'receipts_snoerror.htm'
			),
			'correction'=>array(
				'title'=>'Коррекция',
				'inc'=>'receipts_correction.htm'
			),
			'select_tap'=>array(
				'title'=>'Выбор крана',
				'inc'=>'receipts_select_tap.htm'
			),
			'salesreport'=>array(
				'title'=>'Отчет за смену',
				'inc'=>'receipts_salesreport.htm'
			),
			'add_cocktail_line'=>array(
				'title'=>'Добавить маркированную позицию в коктейль',
				'inc'=>'receipts_add_cocktail_line.htm'
			),
			'certificates'=>array(
				'title'=>'Добавленные сертификаты',
				'inc'=>'receipts_certificate.htm'
			),
			'add_certificate'=>array(
				'title'=>'Укажите номер сертификата',
				'inc'=>'receipts_add_certificate.htm'
			),
			'add_certificate2receipt'=>array(
				'title'=>'Укажите номер сертификата',
				'inc'=>'receipts_add_certificate2receipt.htm'
			),
			'select_certificate'=>array(
				'title'=>'Выберите сертификат',
				'inc'=>'receipts_select_certificate.htm'
			),
			'printdoc'=>array(
				'title'=>'Печать документов',
				'inc'=>'receipts_printdoc.htm'
			),
		);
		$pages[$page]['page']=$page;
		return $pages[$page];
	}

	// Выбираем чеки
	function select_receipts($query=null, $options=null) {
		if(!$query) {
			$query=array('r.id>?', 0); // чтобы хоть что-то вставить в фильтры
		}

		// формируем сортировку и лимиты
		$option='';
		if($options['order']) {
			$option.=' ORDER BY '.$options['order'];
		}
		if($options['limit']) {
			$option.=' LIMIT '.$options['limit'];
		}
		// собственно сам запрос
		$receipts=array();
		$sql="SELECT COALESCE((SELECT CASE MIN(l.issued_order) WHEN 0 THEN 0 ELSE MAX(l.issued_order) END AS max_issued_order FROM receiptlines AS l WHERE l.receipt_id=r.id), r.time) AS issued_order, r.*, u.name, u.short_name, g.title, t.title AS table_title, room.id AS room_id, room.title AS room_title, e.title AS epay_title FROM receipts AS r LEFT JOIN users AS u ON u.id=r.user_id LEFT JOIN usergroups AS g ON g.id=u.group_id LEFT JOIN tables AS t ON t.id=r.table_id LEFT JOIN rooms AS room ON room.id=t.room LEFT JOIN epays_settings AS e ON e.id=r.epay WHERE (".$query[0].") AND r.time>0 ".$option;
		$receipts=$this->db->exec($sql, $query[1]);
		$receiptlines=new \Models\Receiptlines($this->db, $this->f3);

		$partners=array();
		if(mb_stripos($this->f3->get('SERVER.SERVER_SOFTWARE'), 'ksweb')>0) {
			$partners[]='ksweb';
		}
		if($this->f3->get('neva')===true) {
			$partners[]='neva';
		}

		foreach ($receipts as $n => $r) {
			if(!is_numeric($r['discount'])) {
				$r['discount']=(float)$r['discount'];
				$receipts[$n]['discount']=$r['discount'];
			}
			if($r['type']==$this->f3->get('receipt_sales') || $r['type']==$this->f3->get('receipt_return') || $r['type']==$this->f3->get('receipt_chpok') || $r['type']==$this->f3->get('receipt_keg_connection') || $r['type']==$this->f3->get('receipt_correct_sales') || $r['type']==$this->f3->get('receipt_correct_return') || $r['type']==$this->f3->get('receipt_writeoff')) {
				$receipts[$n]['receiptlines']=$receiptlines->select_lines(array('receipt_id=?', $r['id']));
				if($receipts[$n]['lines_count']==null) {
					$receipts[$n]['lines_count']=$receipts[$n]['lines_count_add']=count($receipts[$n]['receiptlines']);
				}
			}
			else {
				unset($receipts[$n]['lines_count']);
			}
			$receipts[$n]['data']=json_decode($r['other_data'], true);
			if(is_numeric($receipts[$n]['data']['partner']['inn']) && (($receipts[$n]['data']['partner']['ie']==1 && mb_strlen($receipts[$n]['data']['partner']['inn'])==12) || mb_strlen($receipts[$n]['data']['partner']['inn'])==10)) {
				$receipts[$n]['data']['partner']['ur']=1;
			}
			$receipts[$n]['paymentmethods']=json_decode($r['payment'], true);
			$receipts[$n]['partners']=$partners;
		}
		return $receipts;
	}

	function gen_order_number($sets, $id) {
		$n=$sets['orders_type'];
		$number=mb_substr($id, -$sets['orders_type']);
		$l=mb_strlen($number);
		if($l<$sets['orders_type']) {
			$number=str_repeat('0', $sets['orders_type']-$l).$number;
		}

		return $sets['prefix'].$number;
	}

	// Узнаем окрытый чек
	function get_open_receipt($sets, $open=true, $all_user=0, $type_id=null) {
		$rm=$sets['rm'];
		$store=$sets['store'];
		$this->reset();
		$user_id=$this->f3->get('authorization_user.id');
		$receipt_id=$this->f3->get('COOKIE.receipt_id');
		$table_id=$this->f3->get('COOKIE.table_id');
		if(!$table_id) $table_id=0;
		if($table_id>0) {
			$t=new \Models\Tables($this->db, $this->f3);
			$table=$t->select_tables(array('id=?', $table_id), array('limit'=>1));
			$r=new \Models\Rooms($this->db, $this->f3);
			$room=$r->select_rooms(array('id=?', $table[0]['room']), array('limit'=>1));
			$table[0]['room_title']=$room[0]['title'];
		}
		$user_all='';
		if($all_user) {
			//$user_all=' OR user_id>0';
		}

		$type_where='';
		if($type_id>0) {
			$type_where=' AND type='.$type_id;
		}
		else {
			$type_where=' AND (type NOT IN('.$this->f3->get('receipt_print').', '.$this->f3->get('receipt_writeoff').', '.$this->f3->get('receipt_change_open').', '.$this->f3->get('receipt_change_close').') OR type IS NULL)';
		}

		$this->load(array('rm=? AND store=? AND time=0 AND (user_id=? '.$user_all.' ) AND table_id=? '.$type_where, array($rm, $store, $user_id, $table_id)));
		if($this->dry()) {
			if(!$open) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$receipt=array(
				'rm'=>$rm,
				'store'=>$store,
				'user_id'=>$user_id,
				'table_id'=>$table_id,
				'table'=>$table[0],
				'time'=>0,
				'type'=>$type_id
			);
			$this->copyFrom($receipt);
			if($this->insert()) {
				$receipt['id']=$this->get('_id');
				$receipt['order_number']=$this->gen_order_number($sets, $receipt['id']);
				$this->copyFrom($receipt);
				$this->update();
				return array(
					'success'=>true,
					'txt'=>'save_successful',
					'receipt'=>$receipt,
					'open'=>array()
				);
			}
			else {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
		}
		else {
			$receipt=array();
			$open=array();
			do {
				$ticket=$this->cast();
				if(!is_numeric($ticket['discount'])) {
					$ticket['discount']=0;
				}
				if($ticket['id']==$receipt_id) {
					$receipt=$ticket;
				}
				else {
					$open[]=$ticket;
				}
			}
			while($this->skip());
			if(empty($receipt)) {
				$receipt=$open[0];
			}
			if($receipt['partner_id']>0) {
				$p=new \Models\Partners($this->db, $this->f3);
				$partner=$p->select_partner(array('partner_id=?', $receipt['partner_id']), array('limit'=>1));
				$receipt['partner']=$partner[0];
			}
			elseif($receipt['partner_id']<0) {
				$partner_name='Новый клиент';
				$other_data=json_decode($receipt['other_data'], true);
				if(is_array($other_data) && isset($other_data['partner']['name']) && $other_data['partner']['name']!='') $partner_name=$other_data['partner']['name'];
				$receipt['partner']=array(
					'name'=>$partner_name,
					'card'=>$receipt['card'],
					'phone'=>$receipt['client']
				);
			}
			$receipt['table']=$table[0];

			// Узнаем какие сертификаты были добавлены в чек
			$c=new \Models\Certificates($this->db, $this->f3);
			$receipt['certificates']=$c->receipt_certificates($receipt['id']);

			return array(
				'success'=>true,
				'receipt'=>$receipt,
				'open'=>$open
			);
		}
	}

	// Ищем чеки
	function search($id, $changes, $barcode, $dates, $type, $start=0, $limit=30) {
		$where='r.type!=? AND r.rm=?';
		$val=array($this->f3->get('receipt_walk'), $this->f3->get('api_data.rm_id'));
		if($id) {
			$where.=' AND r.id=?';
			$val[]=$id;
		}
		if($changes) {
			$where.=' AND r.changes=?';
			$val[]=$changes;
		}
		if($dates) {
			if($where!='')$where.=' AND ';
			$where.='r.time>=? AND r.time<=?';
			$val[]=$dates[0];
			$val[]=$dates[1]+3600*24;
		}
		if($type) {
			if($where!='')$where.=' AND ';
			$where.='r.type=?';
			$val[]=$type;
		}
		if($barcode) {
			if($where!='') $where.=' AND ';
			$p=new \Models\Products($this->db, $this->f3);
			$products=$p->search($barcode, null, null, true);
			if($products['success']) {
				$product_id=$products['products'][0]['id'];
				$receiptlines=new \Models\Receiptlines($this->db, $this->f3);
				$lines=$receiptlines->select_lines(array('product_id=?', $product_id));
				if($lines) {
					$bwhere='';
					foreach ($lines as $l) {
						if($bwhere!='')$bwhere.=' OR ';
						$bwhere.=' r.id=? ';
						$val[]=$l['receipt_id'];
					}
					if($bwhere!='') {
						$where.=' ('.$bwhere.') ';
					}
				}
				else {
					$where.='r.id=?';
					$val[]=-1;
				}
			}
			else {
				$where.='r.id=?';
				$val[]=-1;
			}
		}
		if(!$where) {
			$where='r.id>?';
			$val[]=0;
		}
		$receipts=$this->select_receipts(array($where, $val), array('order'=>'time DESC', 'limit'=>$start.', '.$limit));
		$sql="SELECT COUNT(*) AS count FROM receipts AS r WHERE ".$where;
		$res=$this->db->exec($sql, $val);
		$count=$res[0]['count'];

		return array(
			'success'=>true,
			'count'=>$count,
			'receipts'=>$receipts
		);
	}

	// Проверка правильности заполнения контактных данных покупателя
	function client_validate($client) {
		$client=str_replace(' ', '', $client);
		$client=str_replace('(', '', $client);
		$client=str_replace(')', '', $client);

		$first=mb_substr($client, 0, 1);
		$cl=str_replace('-', '', $client);
		if($first=='+' || is_numeric($cl)) {
			// Значит это номер телефона
			if($first=='+') {
				$client=mb_substr($cl, 1);
			}
			elseif($first=='8') {
				$client='7'.mb_substr($cl, 1);
			}
			elseif($first=='9') {
				$client='7'.$cl;
			}
			else {
				$client=$cl;
			}
			if(mb_strlen($client)!=11) {
				return array(
					'success'=>false,
					'txt'=>'incorrect_email_or_phone'
				);
			}
		}
		else {
			// проверяем e-mail
			if(!filter_var($client, FILTER_VALIDATE_EMAIL)) {
				return array(
					'success'=>false,
					'txt'=>'incorrect_email_or_phone'
				);
			}
		}
		return array(
			'success'=>true,
			'client'=>$client
		);
	}

	// Пробиваем чек
	function add_ticket($receipt_id, $change, $type, $paymentmethod, $client_sum, $sum, $lines, $client, $discount=0, $partner_id=0, $sales_receipts=0, $print=1, $partner_bonus=0, $partner_bonus_sum=0, $bonus_pay=0, $executor=0, $correct_type=0, $osn_number=0, $osn_date='', $slip='', $bonus_add=0, $epay=0, $ignore_max_discount=0, $sno=false, $fpd=false, $psr=4) {
		$sets=$this->f3->get('base_settings');
		if($client) {
			$client_validate=$this->client_validate($client);
			if(!$client_validate['success']) {
				return $client_validate;
			}
			else {
				$client=$client_validate['client'];
			}
		}
		if(is_array($lines)) {
			$lines_count=count($lines);
		}
		else {
			$lines_count=0;
		}
		if($lines_count==0) {
			return array(
				'success'=>false,
				'txt'=>'lines_not_found'
			);
		}

		// Формируем данные оплаты
		$ticket_sum=round($sum, 2);
		$payment=array();
		$p=new \Models\Paymentmethods($this->db, $this->f3);
		$paymentmethods=$p->select_method();
		$paymentmethods=array_combine(array_column($paymentmethods, 'id'), $paymentmethods);
		$cash=1;
		$pays_sum=0;
		foreach ($paymentmethod as $p_id) {
			$p_sum=round($client_sum[$p_id], 2);
			$payment[]=array('method'=>$p_id, 'sum'=>$p_sum);
			if($paymentmethods[$p_id]['cash']==0) $cash=0;
			$pays_sum+=$p_sum;
		}
		
		if($pays_sum<$ticket_sum) {
			return array(
				'success'=>false,
				'txt'=>'pay_sum_less'
			);
		}

		if($cash==0 && $pays_sum!=$ticket_sum) {
			return array(
				'success'=>false,
				'txt'=>'pay_sum_error'
			);
		}

		// формируем данные чека
		$receipt=array(
			'id'=>$receipt_id,
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>0,
			'type'=>$type,
			'payment'=>json_encode($payment),
			'sum'=>$ticket_sum,
			'client'=>$client,
			'partner_id'=>$partner_id,
			'lines_count'=>$lines_count,
			'correct_type'=>$correct_type,
			'osn_number'=>$osn_number,
			'osn_date'=>$osn_date,
			'slip'=>$slip,
			'bonus_pay'=>$bonus_pay,
			'bonus_add'=>$bonus_add,
			'epay'=>$epay,
			'sno'=>$sno,
			'psr'=>$psr
		);
		if($fpd) {
			$receipt['fpd']=$fpd;
		}
		if($executor) {
			$receipt['executor']=$executor;
		}
		$nofr=$this->f3->get('POST.nofr');
		if($nofr) {
			$receipt['nofr']=$nofr;
		}
		
		$this->reset();
		$this->load(array('id=?', $receipt_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$ticket=$this->cast();

		if($type==$this->f3->get('receipt_writeoff')) {
			$other_data=json_decode($ticket['other_data'], true);
			if(!is_array($other_data)) {
				$other_data=array();
			}
			$other_data['writeoff_data']=array(
				'TypeWriteOff'=>$this->f3->get('REQUEST.writeoff')
			);
			$ticket['other_data']=json_encode($other_data);
		}

		if($ticket['table_id']) {
			$t=new \Models\Tables($this->db, $this->f3);
			$table=$t->select_tables(array('id=?', $ticket['table_id']), array('limit'=>1));
			$r=new \Models\Rooms($this->db, $this->f3);
			$room=$r->select_rooms(array('id=?', $table[0]['room']), array('limit'=>1));
			$table[0]['room_title']=$room[0]['title'];
			$ticket['table']=$table[0];
		}
		$receipt['other_data']=$ticket['other_data'];
		$receipt['receipt']=$ticket;

		$this->copyFrom($receipt);
		if(!$this->update()) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		$egais=array();
		if($this->egais_sign) {
			$egais=json_decode($this->egais_sign, true);
		}
		if($receipt['type']!=$this->f3->get('receipt_writeoff')) {
			if(!$egais) {
				foreach($lines as $n=>$l) {
					$lines[$n]['psr']=$psr;
				}
				$fr_result=$this->fr->ticket($receipt, $lines, $sum, $discount, $sales_receipts, $print, $egais, $partner_bonus, $partner_bonus_sum, $bonus_pay, null, $ignore_max_discount, $sno);
			}
		}
		else {
			$payment=array(
				array(
					'method'=>0,
					'sum'=>0
				)
			);
			$receipt['payment']=json_encode($payment);
		}
		if(isset($fr_result['success']) && $fr_result['success']===false) {
			return $fr_result;
		}
		if(isset($fr_result['show_qr'])) {
			return $fr_result;
		}
		if(isset($fr_result['fd']) && isset($fr_result['fp'])) {
			$receipt['fd']=$fr_result['fd'];
			$receipt['fp']=$fr_result['fp'];
			$receipt['kkm_time']=$fr_result['kkm_time'];
			$receipt['fn']=$this->f3->get('fn');
		}
		if(isset($fr_result['slip']) && $fr_result['slip']!='') {
			$receipt['slip']=$fr_result['slip'];
		}
		$receipt['time']=microtime(true);

		// Проверяем наличие алкоголя в чеке
		$no_egais=$this->f3->get('no_egais');
		if(!$no_egais && ($this->egais_sign=='' || (isset($egais['success']) && $egais['success']===false)) && (int)$this->egais->sets['egais']==1) {
			if($type==$this->f3->get('receipt_writeoff')) {
				$egais=$this->egais->receipt_writeoff($receipt_id, $lines, $other_data['writeoff_data']['TypeWriteOff']);
			}
			else {
				if($type==$this->f3->get('receipt_return')) $return=true;
				else $return=false;
				$egais=$this->egais->cheque_v4($change['id'], $receipt_id, $lines, $return);
			}
			$receipt['egais_sign']=json_encode($egais);
			$receipt['egais_xml']=$egais['egais_xml'];
			if(isset($egais['success']) && $egais['success']===false) {
				$egais['txt']=$egais['error'];
				$receipt['time']=0;
			}
		}
		if(isset($egais['success']) && $no_egais) $egais['success']=true;

		if($egais['sign'] && (int)$sets['egais_print_qr']==1) {
			$egais_strs="p;".$egais['sign'].";\n";
			$egais_strs.="qr;".$egais['url'].";\n";
			$egais_strs.="p;".$egais['url'].";\n";
			$this->fr->send_ajax($egais_strs);
		}
		$this->copyFrom($receipt);
		if(!$this->update()) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}

		if(isset($egais['success']) && $egais['success']===false) {
			return $egais;
		}


		$res=array(
			'success'=>true,
			'txt'=>'save_successful',
			'slip'=>$receipt['slip'],
			'receipt'=>$receipt
		);
		if(isset($fr_result['sales_receipts']) && $fr_result['sales_receipts']==1)  {
			$res['sales_receipts']=$fr_result['sales_receipts'];
		}
		return $res;
	}

	function ticket_chpok($rm, $store, $change, $sum=0) {
		// формируем данные чека
		$receipt=array(
			'user_id'=>$this->f3->get('authorization_user.id'),
			'rm'=>$rm,
			'store'=>$store,
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>0,
			'type'=>$this->f3->get('receipt_chpok'),
			'payment'=>json_encode(array()),
			'sum'=>round($sum, 2),
			'client'=>'',
			'partner_id'=>0,
			'lines_count'=>1
		);
		$nofr=$this->f3->get('POST.nofr');
		if($nofr) {
			$receipt['nofr']=$nofr;
		}
		$this->reset();
		$this->copyFrom($receipt);
		if(!$this->insert()) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		$receipt['id']=$this->get('_id');

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'id'=>$receipt['id'],
			'receipt'=>$receipt
		);
	}

	function ticket_return($rm, $store, $change, $post, $lines=array()) {
		if(!$lines) {
			$lines=$post['receiptlines'];
		}
		else {
			$post['receiptlines']=$lines;
		}
		if(is_array($post['receiptlines'])) $lines_count=count($post['receiptlines']);
		else $lines_count=0;
		if($lines_count==0) {
			return array(
				'success'=>false,
				'txt'=>'lines_not_found'
			);
		}

		// Формируем данные оплаты
		$payment=array();
		foreach ($post['paymentmethod'] as $p_id) {
			$payment[]=array('method'=>$p_id, 'sum'=>round($post['client_sum'][$p_id], 2));
		}

		// формируем данные чека
		$other_data=array('parent_id'=>(int)$post['parent_id']);
		$receipt=array(
			'user_id'=>$this->f3->get('authorization_user.id'),
			'rm'=>$rm,
			'store'=>$store,
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>0,
			'type'=>$post['type'],
			'payment'=>json_encode($payment),
			'sum'=>round($post['sum'], 2),
			'client'=>'',
			'partner_id'=>$post['partner_id'],
			'lines_count'=>$lines_count,
			'epay'=>$post['epay'],
			'sno'=>$post['sno'],
			'psr'=>$post['psr'],
			'executor'=>$post['executor'],
			'bonus_add'=>$post['bonus_add'],
			'bonus_pay'=>$post['bonus_pay'],
			'other_data'=>json_encode($other_data)
		);
		$nofr=$this->f3->get('hold');
		if($nofr) {
			$receipt['nofr']=$nofr;
		}
		$this->reset();
		$this->copyFrom($receipt);
		if(!$this->insert()) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		$receipt['id']=$this->get('_id');

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'id'=>$receipt['id'],
			'receipt'=>$receipt
		);
	}

	// Проводим чек возврата
	function ticket_ready($receipt, $post, $lines=array()) {
		$sets=$this->f3->get('base_settings');
		if(!$lines) {
			$lines=$post['receiptlines'];
		}
		else {
			$post['receiptlines']=$lines;
		}
		$this->reset();
		$this->load(array('id=?', $receipt['id']), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$this->time=microtime(true);
		$egais=array();
		if($this->egais_sign) {
			$egais=json_decode($this->egais_sign, true);
		}
		
		if($this->table_id) {
			$t=new \Models\Tables($this->db, $this->f3);
			$table=$t->select_tables(array('id=?', $this->table_id), array('limit'=>1));
			$r=new \Models\Rooms($this->db, $this->f3);
			$room=$r->select_rooms(array('id=?', $table[0]['room']), array('limit'=>1));
			$table[0]['room_title']=$room[0]['title'];
			$receipt['table']=$table[0];
		}
		$receipt['receipt']=$receipt;
		foreach($post['receiptlines'] as $n=>$l) {
			$post['receiptlines'][$n]['psr']=$post['psr'];
		}
		if(!$egais) {
			$fr_result=$this->fr->ticket($receipt, $post['receiptlines'], $post['sum'], $post['discount'], 0, 1, $egais, null, null, null, $post, null, $post['sno']);
		}
		if(isset($fr_result['fd']) && isset($fr_result['fp'])) {
			$this->fd=$fr_result['fd'];
			$this->fp=$fr_result['fp'];
			$this->kkm_time=$fr_result['kkm_time'];
			$this->fn=$this->f3->get('fn');
		}
		if($fr_result['slip']) {
			$this->slip=$fr_result['slip'];
		}

		$no_egais=$this->f3->get('no_egais');
		if(!$no_egais && in_array("1", array_column($post['receiptlines'], 'egais')) && $egais['success']!==true) {
			$egais=$this->egais->cheque_v4($receipt['changes'], $receipt['id'], $post['receiptlines'], true);
			if($egais) {
				$this->egais_sign=json_encode($egais);
				$this->egais_xml=$egais['egais_xml'];
			}
		}
		if(isset($egais['success']) && $no_egais) $egais['success']=true;
		if($egais['sign'] && (int)$sets['egais_print_qr']==1) {
			$egais_strs="p;".$egais['sign'].";\n";
			$egais_strs.="qr;".$egais['url'].";\n";
			$egais_strs.="p;".$egais['url'].";\n";
			$this->fr->send_ajax($egais_strs);
		}


		if($this->update()) {

			if(isset($egais['success']) && $egais['success']===false) {
				$egais['txt']=$egais['error'];
				return $egais;
			}

			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'function'=>'return_reset()'
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Проводим вскрытие бутылки
	function ticket_chpok_ready($receipt, $product) {
		$sets=$this->f3->get('base_settings');
		$this->reset();
		$this->load(array('id=?', $receipt['id']), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$this->time=microtime(true);
		if((int)$this->egais->sets['egais']==1 && (int)$product[0]['egais']===1) {
			if(!in_array($product[0]['barcode'], array_column($product[0]['barcodes'], 'barcode'))) {
				$this->db->exec("INSERT INTO barcodes (product_id, barcode) VALUES (?, ?)", array($product[0]['id'], $product[0]['barcode']));
			}
			$product[0]['count']=$product[0]['quantity'];
			$product[0]['unit_okei']=$product[0]['units'];
			if((int)$sets['egais_chpok_mode']==2) {
				$egais=$this->egais->cheque_v4($receipt['changes'], $receipt['id'], $product, false);
				if($egais) {
					$this->egais_sign=json_encode($egais);
					$this->egais_xml=$egais['egais_xml'];
				}
			}
			$mark=json_decode($product[0]['mark'])[0];
			$this->db->exec("UPDATE egais_marks SET chpok=1 WHERE mark=?", $mark);
		}

		if($this->update()) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Чек смены
	function ticket_change($api_data, $change, $type, $paymentmethod, $sum=0, $slip='') {
		$id=0;
		$this->reset();
		$this->load(array('rm=? AND type=? AND time=0 AND changes=?', array($api_data['rm_id'], $type, $change['id'])), array('limit'=>1));
		if(!$this->dry()) {
			$id=$this->id;
			if($slip=='') $slip=$this->slip;
		}
		if(!isset($change['time'])) {
			$change['time']=microtime(true);
		}
		$sum=round($sum, 2);
		// Формируем данные оплаты
		$payment[]=array('method'=>$paymentmethod, 'sum'=>$sum);
		// формируем данные чека
		$receipt=array(
			'store'=>$api_data['store_id'],
			'rm'=>$api_data['rm_id'],
			'user_id'=>$this->f3->get('authorization_user.id'),
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>$change['time'],
			'type'=>$type,
			'payment'=>json_encode($payment),
			'sum'=>$sum,
			'client'=>'',
			'partner_id'=>0,
			'slip'=>$slip
		);
		$this->copyFrom($receipt);
		if($this->save()) { // сохраняем
			if($id==0)$id=$this->get('_id');
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'id'=>$id,
				'slip'=>$slip
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Удаление чека
	function delete_receipt($id) {
		$this->reset();
		$this->load(array('id=?', $id), array('limit'=>1));
		$this->erase();
		$this->db->exec("DELETE FROM receiptlines WHERE receipt_id=?", $id);
	}

	// Внесение и изъятие денег из кассы
	function cashin($api_data, $change, $pay, $sum, $type, $create_receipt=0, $description='', $print_type=null) {
		$sum=round($sum, 2);
		$this->fr->cashin($change['id'], $sum, $print_type);
		$receipt=array(
			'store'=>$api_data['store_id'],
			'rm'=>$api_data['rm_id'],
			'user_id'=>$this->f3->get('authorization_user.id'),
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>microtime(true),
			'type'=>$type,
			'payment'=>json_encode(array(array('method'=>$pay, 'sum'=>$sum))),
			'sum'=>$sum,
			'client'=>'',
			'create_receipt'=>$create_receipt,
			'description'=>$description
		);
		$nofr=$this->f3->get('hold');
		if($nofr) {
			$receipt['nofr']=$nofr;
		}
		$this->reset();
		$this->copyFrom($receipt);
		$this->save();
		if($this->get('_id')) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'form_reset'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Статистика по смене
	function change_statistic($change) {
		$receipts=$this->select_receipts(array('r.changes=? AND r.type!=? AND r.type!=?', array($change, $this->f3->get('receipt_change_open'), $this->f3->get('receipt_change_close'))));
		$report=array(
			$this->f3->get('receipt_sales')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_return')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_cashin')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_cashout')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_writeoff')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_keg_connection')=>array('sum'=>0, 'count'=>0),
			$this->f3->get('receipt_chpok')=>array('sum'=>0, 'count'=>0),
			'receipt_remote'=>array('sum'=>0, 'count'=>0),
		);
		foreach ($receipts as $r) {
			if($r['type']==128) $r['type']=1;
			elseif($r['type']==130) $r['type']=2;
			$report[$r['type']]['count']+=1;
			$report[$r['type']]['sum']+=round($r['sum'], 2);
			$pays=json_decode($r['payment'], true);
			if(is_array($pays)) {
				foreach ($pays as $p) {
					if(!$p['sum'])$p['sum']=0;
					if($p['sum']>$r['sum']) {
						$p['sum']=round($r['sum'], 2);
					}
					$report[$r['type']]['pay'][$p['method']]+=round($p['sum'], 2);
					if($r['epay']>0 && $p['method']==2) {
						$report[$r['type']]['epay'][$r['epay']]['sum']+=round($p['sum'], 2);
						$report[$r['type']]['epay'][$r['epay']]['count']+=1;
					}
					if($r['remote']>0) {
						$report['receipt_remote']['pay'][$p['method']]+=round($p['sum'], 2);
						$report['receipt_remote']['count']+=1;
						$report['receipt_remote']['sum']+=round($r['sum'], 2);
					}
				}
			}
		}
		return $report;
	}

	// Отчет по секциям
	function rep_sections() {
		$fr_type=$this->fr->get_fr()['type'];
		if($fr_type==1) {
			$this->fr->rep_sections();
			return array(
				'success'=>true,
				'txt'=>'report_is_ready'
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'fr_only'
			);
		}
	}

	// Печать копии последнего чека
	function print_last() {
		if($this->fr->sets['active']) {
			$this->fr->c();
			return array(
				'success'=>true,
				'txt'=>'request_has_been_sent'
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'kkm_is_not_activity'
			);
		}
	}

	// Открытие нового пустого чека
	function open_new($sets) {
		$rm=$sets['rm'];
		$store=$sets['store'];
		$user_id=$this->f3->get('authorization_user.id');
		$table_id=$this->f3->get('COOKIE.table_id');
		if(!is_numeric($table_id)) $table_id=0;
		$this->reset();
		$receipt=array(
			'rm'=>$rm,
			'store'=>$store,
			'user_id'=>$user_id,
			'table_id'=>$table_id,
			'time'=>0
		);
		$this->copyFrom($receipt);
		if($this->insert()) {
			$receipt['id']=$this->get('_id');
			$receipt['order_number']=$this->gen_order_number($sets, $receipt['id']);
			$this->copyFrom($receipt);
			$this->update();
			$this->f3->set('COOKIE.receipt_id', $receipt['id']);
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'reload_menu'=>true,
				'close_all_window'=>true,
				'receipt_id'=>$receipt['id']
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Переключение на другой чек
	function switch_receipt($id) {
		if(!$id) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}
		$this->reset();
		$this->load(array('id=?', $id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$this->f3->set('COOKIE.receipt_id', $this->id);
		$this->f3->set('COOKIE.table_id', $this->table_id);
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'function'=>'check_window_table()',
			'reload_menu'=>true,
			'close_all_window'=>true
		);
	}

	// Добавление клиента к чеку
	function add_partner($receipt_id, $partner) {
		$this->reset();
		$this->load(array('id=? AND time=0', $receipt_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		if($this->slip!='') {
			return array(
				'success'=>false,
				'txt'=>'dont_change_payed_receipt'
			);
		}
		$this->partner_id=$partner['partner_id'];
		if($partner['email']) {
			$contact=$partner['email'];
		}
		else {
			$contact=$partner['phone'];
		}
		$this->client=$contact;
		$this->discount=$partner['discount'];
		$this->card=$partner['card'];
		$other=json_decode($this->other_data, true);
		if(!is_array($other)) {
			$other=array();
		}
		$other['partner']=$partner;
		$this->other_data=json_encode($other);
		if($this->update()!==false) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Очистка чека
	function receipt_clear($id) {
		$this->reset();
		$this->load(array('id=?', $id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$this->partner_id='';
		$this->discount=0;
		$this->card='';
		$this->bonus_pay=0;
		$this->client='';
		$this->description='';
		$this->payment='';
		$this->sno='';
		$this->egais_sign='';
		$this->egais_xml='';
		$this->other_data='';
		if($this->update()) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Убрать клиента из чека
	function remove_partner($id) {
		$this->reset();
		$this->load(array('id=?', $id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		if($this->slip!='') {
			return array(
				'success'=>false,
				'txt'=>'dont_change_payed_receipt'
			);
		}
		$this->partner_id='';
		$this->discount=0;
		$this->card='';
		$this->bonus_pay=0;
		$this->client='';
		$other=json_decode($this->other_data, true);
		if(is_array($other)) {
			unset($other['partner']);
			if(empty($other)) $this->other_data='';
			else $this->other_data=json_encode($other);
		}
		if($this->update()) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Сохранение произвольной скидки в чек
	function set_discount($discount) {
		if($discount=='.') $discount=0;
		if(is_numeric($discount)) {
			$user=$this->f3->get('authorization_user');
			if(!in_array('receipts/discount', $user['module']) && $discount>0) {
				// Значит нельзя устанавливать произвольную скидку
				// Проверяем можно ли указать такую скидку
				$loyalty_models=new \Models\Loyalty($this->db, $this->f3);
				if(!$loyalty_models->select_discounts($discount)) {
					return array(
						'success'=>false,
						'txt'=>'incorrect_select_discount'
					);
				}
			}
			$this->reset();
			$id=$this->f3->get('COOKIE.receipt_id');
			$this->load(array('id=?', $id), array('limit'=>1));
			if($this->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			if($this->slip!='' && (float)$this->discount!=(float)$discount) {
				return array(
					'success'=>false,
					'save_discount'=>(float)$this->discount,
					'txt'=>'dont_change_payed_receipt'
				);
			}
			$this->discount=$discount;
			if($this->update()!==false) {
				return array(
					'success'=>true,
					'txt'=>'save_successful',
					'reload'=>array('.receiptlines')
				);
			}
			else {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'incorrect_select_discount'
			);
		}
	}

	// Поиск всех открытых чеков
	function all_open($table_id=0) {
		$sql="SELECT r.*, u.name, u.short_name, g.title, rooms.title AS room_title, rooms.id AS room_id, t.title AS table_title, p.name AS partner_name FROM receipts AS r LEFT JOIN users AS u ON u.id=r.user_id LEFT JOIN usergroups AS g ON g.id=u.group_id LEFT JOIN tables AS t ON t.id=r.table_id LEFT JOIN rooms ON rooms.id=t.room LEFT JOIN partners AS p ON p.partner_id=r.partner_id WHERE r.time=0 AND (r.type NOT IN (".$this->f3->get('receipt_print').", ".$this->f3->get('receipt_writeoff').") OR r.type IS NULL)";
		$val=array();
		if($table_id>0) {
			$sql.=' AND r.table_id=?';
			$val[]=$table_id;
		}
		$result=$this->db->exec($sql, $val);
		$receipts=array();
		if($result) {
			$receiptlines=new \Models\Receiptlines($this->db, $this->f3);
			foreach($result as $r) {
				$lines=$receiptlines->select_lines(array('receipt_id=?', $r['id']), array('order'=>'turn, id'));
				$summ=$receiptlines->get_sum($lines, $r['receipt']['discount']);
				$r['lines']=$summ['lines'];
				$r['lines_sum']=$summ['sum'];
				$r['lines_count']=$summ['lines']?count($summ['lines']):0;
				$r['rm_name']=$this->f3->get('api_data.rm_name');
				if($r['lines_count']>0 || $r['description']!='') {
					$receipts[]=$r;
				}
			}
		}
		return array(
			'success'=>true,
			'receipts'=>$receipts
		);
	}

	function all_order_create($kitchen=1, $bar=1, $id_kitchen=0, $id_bar=0) {
		$kitchen_where='';
		$bar_where='';
		if($kitchen==1) {
			if(is_numeric($id_kitchen) && $id_kitchen>=0) {
				$kitchen_where=' AND (l.kitchen=1 AND l.print_group_id='.$id_kitchen.') ';
			}
			else {
				$kitchen_where=' AND l.kitchen=1 ';
			}
		}
		else {
			$kitchen_where='';
		}
		if($bar==1) {
			if(is_numeric($id_bar) && $id_bar>=0) {
				$bar_where=' AND (l.bar=1 AND l.print_group_id='.$id_bar.') ';
			}
			else {
				$bar_where=' AND l.bar=1 ';
			}
		}
		else {
			$bar_where='';
		}
		if($kitchen==1 && $bar==1) {
			if(is_numeric($id_kitchen) && $id_kitchen>=0) {
				$kitchen_where=' (l.kitchen=1 AND l.print_group_id='.$id_kitchen.') ';
			}
			else {
				$kitchen_where=' l.kitchen=1 ';
			}
			if(is_numeric($id_bar) && $id_bar>=0) {
				$bar_where=' (l.bar=1 AND l.print_group_id='.$id_bar.') ';
			}
			else {
				$bar_where=' l.bar=1 ';
			}

			$kitchen_where=' AND ('.$kitchen_where.' OR '.$bar_where.')';
			$bar_where='';
		}
		$sql="SELECT l.*, r.order_number AS order_number, r.description AS order_description, room.title AS room_title, t.title AS table_title FROM receiptlines AS l JOIN receipts AS r ON r.id=l.receipt_id LEFT JOIN tables AS t ON t.id=r.table_id LEFT JOIN rooms AS room ON room.id=t.room WHERE l.create_order>0 AND l.complite_order=0 ".$kitchen_where." ".$bar_where." ORDER BY l.create_order, l.turn";
		$receipts=$this->db->exec($sql);
		$result=array();
		if($receipts) {
			foreach($receipts as $r) {
				if($r['parent_id']>0) {
					$result[$r['order_number']][$r['turn']]['lines'][$r['parent_id']]['modifiers'][$r['id']]=$r;
				}
				else {
					$result[$r['order_number']][$r['turn']]['id']=$r['receipt_id'];
					$result[$r['order_number']][$r['turn']]['room_title']=$r['room_title'];
					$result[$r['order_number']][$r['turn']]['table_title']=$r['table_title'];
					$result[$r['order_number']][$r['turn']]['lines'][$r['id']]=$r;
					if($r['create_order']<$result[$r['order_number']][$r['turn']]['create_order'] || !$result[$r['order_number']][$r['turn']]['create_order']) {
						$result[$r['order_number']][$r['turn']]['create_order']=$r['create_order'];
						$result[$r['order_number']][$r['turn']]['order_description']=$r['order_description'];
						$result[$r['order_number']][$r['turn']]['create_order_time']=date('H:i', $r['create_order']);
					}
				}
			}
		}
		return $result;
	}

	function all_order_complite($kitchen=1, $bar=1, $id_kitchen=0, $id_bar=0) {
		$kitchen_where='';
		$bar_where='';
		if($kitchen==1) {
			if(is_numeric($id_kitchen) && $id_kitchen>=0) {
				$kitchen_where=' AND (l.kitchen=1 AND l.print_group_id='.$id_kitchen.') ';
			}
			else {
				$kitchen_where=' AND l.kitchen=1 ';
			}
		}
		else {
			$kitchen_where='';
		}
		if($bar==1) {
			if(is_numeric($id_bar) && $id_bar>=0) {
				$bar_where=' AND (l.bar=1 AND l.print_group_id='.$id_bar.') ';
			}
			else {
				$bar_where=' AND l.bar=1 ';
			}
		}
		else {
			$bar_where='';
		}
		if($kitchen==1 && $bar==1) {
			if(is_numeric($id_kitchen) && $id_kitchen>=0) {
				$kitchen_where=' (l.kitchen=1 AND l.print_group_id='.$id_kitchen.') ';
			}
			else {
				$kitchen_where=' l.kitchen=1 ';
			}
			if(is_numeric($id_bar) && $id_bar>=0) {
				$bar_where=' (l.bar=1 AND l.print_group_id='.$id_bar.') ';
			}
			else {
				$bar_where=' l.bar=1 ';
			}

			$kitchen_where=' AND ('.$kitchen_where.' OR '.$bar_where.')';
			$bar_where='';
		}
		$sql="SELECT l.*, r.order_number AS order_number, r.description AS order_description, room.title AS room_title, t.title AS table_title FROM receiptlines AS l JOIN receipts AS r ON r.id=l.receipt_id LEFT JOIN tables AS t ON t.id=r.table_id LEFT JOIN rooms AS room ON room.id=t.room WHERE l.complite_order>0 AND l.issued_order=0 ".$kitchen_where." ".$bar_where." ORDER BY l.create_order, l.turn";
		$receipts=$this->db->exec($sql);
		$result=array();
		if($receipts) {
			foreach($receipts as $r) {
				if($r['parent_id']>0) {
					$result[$r['order_number']][$r['turn']]['lines'][$r['parent_id']]['modifiers'][$r['id']]=$r;
				}
				else {
					$result[$r['order_number']][$r['turn']]['id']=$r['receipt_id'];
					$result[$r['order_number']][$r['turn']]['lines'][$r['id']]=$r;
					$result[$r['order_number']][$r['turn']]['room_title']=$r['room_title'];
					$result[$r['order_number']][$r['turn']]['table_title']=$r['table_title'];
					if($r['create_order']<$result[$r['order_number']][$r['turn']]['create_order'] || !$result[$r['order_number']][$r['turn']]['create_order']) {
						$result[$r['order_number']][$r['turn']]['create_order']=$r['create_order'];
						$result[$r['order_number']][$r['turn']]['order_description']=$r['order_description'];
						$result[$r['order_number']][$r['turn']]['create_order_time']=date('H:i', $r['create_order']);
					}
				}
			}
		}
		return $result;
	}

	// Поиск всех открытых чеков на других кассах
	function other_all_open($data, $receipts) {
		if(!$data) {
			return $receipts;
		}
		foreach ($data as $ip=>$request) {
			$json=json_decode($request, true);
			if($json['success']) {
				foreach ($json['receipts'] as $receipt) {
					$receipt['ip']=$ip;
					$receipts[]=$receipt;
				}
			}
		}
		return $receipts;
	}

	function other_all_orders($data, $receipts) {
		if(!$data) {
			return $receipts;
		}
		foreach ($data as $ip=>$request) {
			$json=json_decode($request, true);
			if($json['success']) {
				foreach ($json['receipts'] as $key=>$orders) {
					foreach ($orders as $turn=>$receipt) {
						$receipt['ip']=$ip;
						$receipts[$key][$turn]=$receipt;
					}
				}
			}
		}
		return $receipts;
	}

	// Перехват чека
	function intercept($rm, $store, $id) {
		$this->reset();
		$this->load(array('id=? AND time=0', $id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$this->rm=$rm;
		$this->store=$store;

		$this->user_id=$this->f3->get('authorization_user.id');
		$sets=$this->f3->get('base_settings');
		if($sets['cafe_mode']==1) {
			if($this->table_id==0) $this->table_id=$this->f3->get('COOKIE.table_id');
		}
		else {
			$this->table_id=0;
		}
		if($this->update()!==false) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'function'=>'check_window_table()',
				'reload_menu'=>true,
				'receipt'=>$this->cast(),
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Удаление чека с другой кассы
	function other_delete_receipt($ip, $id) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query='http://'.$ip.'/multikassa/delete_receipt?id='.$id;
		$request=$web->request($query, $options);
		return $json=json_decode($request['body'], true);
	}

	// Перехват чека с другой кассы
	function other_intercept($rm, $store, $ip, $id) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query='http://'.$ip.'/multikassa/intercept?id='.$id;
		$request=$web->request($query, $options);
		$json=json_decode($request['body'], true);
		if(!$json['success']) {
			return $json;
		}
		$receipt=$json['receipt'];
		$receipt['rm']=$rm;
		$lines=$json['receiptlines'];
		unset($receipt['id']);
		$user_id=$this->f3->get('authorization_user.id');
		$receipt['user_id']=$user_id;
		$table_id=$this->f3->get('COOKIE.table_id');
		if(!$receipt['table_id'] && $table_id) {
			$receipt['table_id']=$table_id;
		}
		$this->reset();
		$this->copyFrom($receipt);
		if($this->insert()===false) {
			return array(
				'success'=>false,
				'db_error'
			);
		}
		$receipt['id']=$this->get('_id');
		if($lines) {
			$l=new \Models\Receiptlines($this->db, $this->f3);
			foreach ($lines as $line) {
				$l->reset();
				unset($line['id']);
				$line['receipt_id']=$receipt['id'];
				$l->copyFrom($line);
				$l->insert();
			}
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'reload_menu'=>true,
			'receipt'=>$receipt,
			'close_all_window'=>true,

		);
	}

	// Получаем открытый пустой чек
	function get_empty($rm, $store) {
		$sql="SELECT r.id, COUNT(l.id) AS count FROM `receipts` AS `r` LEFT JOIN `receiptlines` AS `l` ON l.receipt_id=r.id WHERE r.time=0 AND r.rm=? AND r.store=? GROUP BY (r.id) ORDER BY r.id";
		$val=array($rm, $store);
		$res=$this->db->exec($sql, $val);
		if($res) {
			foreach ($res as $r) {
				if($r['count']==0) {
					return $r['id'];
				}
			}
		}
		return false;
	}

	// Получаем открытые не пустые чеки
	function get_not_empty($rm, $store) {
		$sql="SELECT COUNT(r.id) AS count FROM `receipts` AS `r` JOIN `receiptlines` AS `l` ON l.receipt_id=r.id WHERE r.time=0 AND r.rm=? AND r.store=? GROUP BY (l.receipt_id)";
		$val=array($rm, $store);
		$res=$this->db->exec($sql, $val);
		return $res[0]['count'];
	}
	
	// Получаем открытые не пустые чеки для стола
	function get_not_empty_for_table($table_id) {
		$sql="SELECT r.*, SUM(l.count) AS lines_count, CASE WHEN l.receipt_id>0 THEN l.receipt_id ELSE r.id END AS r_id FROM receipts AS r JOIN receiptlines AS l ON receipt_id=r.id WHERE r.time=0 AND r.table_id=? GROUP BY r_id";
		$val=array($table_id);
		$res=$this->db->exec($sql, $val);
		return $res;
	}

	// Удаляем открытые чеки
	function delete_open($rm, $store) {
		// Список открытых чеков
		$receipts=$this->db->exec("SELECT `id` FROM `receipts` WHERE `time`=0 AND `rm`=? AND `store`=? AND (`type`!=? OR `type` IS NULL)", array($rm, (int)$store, $this->f3->get('receipt_change_close')));
		if(!empty($receipts)) {
			$in='';
			$val=array();
			foreach ($receipts as $r) {
				if(!empty($val)) {
					$in.=',';
				}
				$in.='?';
				$val[]=$r['id'];
			}
			$sql="DELETE FROM `receipts` WHERE `id` IN (".$in.")";
			$res=$this->db->exec($sql, $val);
			if($res===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
			$sql="DELETE FROM `receiptlines` WHERE `receipt_id` IN (".$in.")";
			$res=$this->db->exec($sql, $val);
			if($res===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
		}

		return array(
			'success'=>true
		);
	}

	// Перемещение чека на другой стол
	function move_receipt($receipt_id, $table_id) {
		if(!$receipt_id || !$table_id) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}
		$this->reset();
		$this->load(array('id=?', $receipt_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$t=new \Models\Tables($this->db, $this->f3);
		$t->load(array('id=?', $table_id), array('limit'=>1));
		if($t->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$this->table_id=$table_id;
		if($this->update()) {
			return array(
				'success'=>false,
				'txt'=>'save_successful',
				'function'=>'$("#screen").load("?table_id='.$table_id.' #screen_window", function(){receiptlines_div_resize();});',
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Добавляем интернет-заказ к чеку
	function push_order($receipt_id, $order) {
		$this->reset();
		$this->load(array('id=?', $receipt_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$this->partner_id=$order['partner_id'];
		$client=$order['partner_email'];
		if(!$client) {
			$client=$order['partner_phone'];
		}
		$this->client=$client;
		$this->discount=$order['partner_discount'];
		$this->description=$order['other']['description'];
		$pays=array();
		if($order['payment']) {
			foreach($order['payment'] as $p) {
				$pays[]=array('method'=>$p[0], 'sum'=>round($p[1], 2));
			}
		}
		$this->payment=json_encode($pays);
		if($order['id']) {
			$this->remote=$order['id'];
		}
		if($this->update()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		if($order['partner_id']) {
			$partner_data=array(
				'card'=>$order['partner_card'],
				'partner_id'=>$order['partner_id'],
				'name'=>$order['partner_title'],
				'email'=>$order['partner_email'],
				'phone'=>$order['partner_phone'],
				'discount'=>$order['partner_discount'],
			);
			$partners=new \Models\Partners($this->db, $this->f3);
			$partner=$partners->save_partner($partner_data);
		}

		if($order['receiptlines']) {
			$lines=new \Models\Receiptlines($this->db, $this->f3);
			foreach ($order['receiptlines'] as $l) {
				$l['id']=$l['product_id'];
				$l['line_discount']=$l['discount'];
				$l['discount']=0;
				$l['price0']=$l['price'];
				if($l['line_discount']!=0) {
					$l['price']=$l['price']-($l['price']*($l['line_discount']/100));
					$l['description']='Установлена скидка';
					$l['loyalty']=2;
				}
				$lines->add_line($receipt_id, $l, $l['count']);
			}
		}

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'reload_menu'=>true,
			'close_all_window'=>true
		);

	}

	// Печать по номеру ФД
	function print_copy_receipt($id) {
		$this->load(array("id=? AND fd!=''", $id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}
		$res=$this->fr->printdoc($this->fd);
		return array(
			'success'=>true
		);
	}

	// Печать пречека или товарного чека
	function print($id, $turn='all', $print=1) {
		$this->reset();
		$this->load(array('id=?', max($id, -1)), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$receipt=$this->cast();
		if($receipt['table_id']) {
			$t=new \Models\Tables($this->db, $this->f3);
			$table=$t->select_tables(array('id=?', $receipt['table_id']), array('limit'=>1));
			$r=new \Models\Rooms($this->db, $this->f3);
			$room=$r->select_rooms(array('id=?', $table[0]['room']), array('limit'=>1));
			$table[0]['room_title']=$room[0]['title'];
			$receipt['table']=$table[0];
		}
		$receipt['receiptlines']=array();
		$receiptlines=new \Models\Receiptlines($this->db, $this->f3);
		$lines=$receiptlines->select_lines(array('receipt_id=?', $receipt['id']), array('order'=>'turn, id'));
		$p=new \Models\Partners($this->db, $this->f3);
		$partner=$p->select_partner(array('partner_id=?', $receipt['partner_id']), array('limit'=>1));
		$base_sets=$this->f3->get('base_settings');
		if($this->printer!='kitchen' && $this->printer!='bar') {
			$lines_sum=$receiptlines->get_sum($lines, $receipt['discount'], $base_sets['round_kop'], $receipt['bonus_pay'], $partner['ignore_max_discount']?$partner['ignore_max_discount']:0);
		}
		else {
			$lines_sum=array(
				'lines'=>$lines
			);
		}
		if(empty($lines_sum['lines'])) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		foreach ($lines_sum['lines'] as $line) {
			if($turn!='all' && $line['turn']!=$turn) {
				continue;
			}
			if($line[$this->printer]==1) {
				continue;
			}
			if(($this->printer=='kitchen' || $this->printer=='bar') && $line['print_group']!=$this->printer) {
				continue;
			}
			$receipt['receiptlines'][]=$line;
		}
		if($receipt['time']>0) {
			$pays=json_decode($receipt['payment'], true);
			$p=new \Models\Paymentmethods($this->db, $this->f3);
			$paymentmethods=$p->select_method();
			foreach ($paymentmethods as $p) {
				$methods[$p['id']]=$p['title'];
			}
			foreach ($pays as $n => $p) {
				$pays[$n]['title']=$methods[$p['method']];
			}
			$receipt['pays']=$pays;
			$u=new \Models\Users($this->db, $this->f3);
			$user=$u->select_users(array('u.id=?', $receipt['user_id']), array('limit'=>1));
			$receipt['user']=$user[0];
		}
		if($receipt['receiptlines']) {
			if($this->fr->sets['line_by_line']==1) {
				$for_print=array();
				foreach ($receipt['receiptlines'] as $line) {
					if($line['parent_id']==0 && !empty($for_print)){
						$res=$this->fr->print($for_print);
						if(is_array($res) && $res['success']===false) return $res;
					}
					if($line['parent_id']==0) {
						$for_print=$receipt;
						$for_print['receiptlines']=array($line);
					}
					else {
						$for_print['receiptlines'][]=$line;
					}
				}
				if(!empty($for_print) && $print==1) {
					$res=$this->fr->print($for_print);
					if(is_array($res) && $res['success']===false) return $res;
				}
			}
			elseif($print==1) {
				$res=$this->fr->print($receipt);
				if(is_array($res) && $res['success']===false) return $res;
			}
			if($this->printer=='kitchen' || $this->printer=='bar') {
				foreach ($receipt['receiptlines'] as $line) {
					$receiptlines->print_ok($line['id'], $this->printer);
				}
			}
		}
		return array(
			'success'=>true
		);
	}

	// Документы отправленные для удаленной фискализации и успешно фискализированные
	function success_fiscalization($time) {
		$receipts=array();
		$this->reset();
		$this->load(array('remote>0 AND time>=?', $time));
		if(!$this->dry()){
			do {
				$receipts[]=$this->remote;
			}
			while ($this->skip());
		}
		return $receipts;
	}

	// Проверка введенного штрих-кода сотрудника
	function validate_walk($data) {
		$s=new \Models\Settings($this->f3, $this->db);
		$sets=$s->get_settings(array('worker_code_pr'));
		if(!$sets['worker_code_pr']) {
			return array(
				'success'=>false,
				'txt'=>'workers_code_is_not_specified'
			);
		}
		$barcode=trim($data['barcode']);
		if(mb_strlen($barcode)!=13 || mb_substr($barcode, 0, mb_strlen($sets['worker_code_pr']))!=$sets['worker_code_pr'] || !ctype_digit($barcode)) {
			return array(
				'success'=>false,
				'txt'=>'incorrect_workers_code'
			);
		}
		$data['barcode']=$barcode;
		return array(
			'success'=>true,
			'data'=>$data
		);
	}

	// Создаем документ прохода сотрудника
	function add_walk($data) {
		$receipt=array(
			'store'=>$data['store'],
			'rm'=>$data['rm'],
			'user_id'=>0,
			'changes'=>0,
			'changes_data'=>'',
			'time'=>microtime(true),
			'type'=>$data['type'],
			'payment'=>'',
			'sum'=>0,
			'client'=>$data['barcode'],
			'create_receipt'=>0,
			'description'=>$data['action']
		);
		$this->reset();
		$this->copyFrom($receipt);
		if($this->save()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'close_all_window'=>true
		);
	}

	// Находим МРЦ - максимальная розничная цена
	function mrc($mrc) {
		$result=0;
		$s=array(
			'A'=>0,'B'=>1,'C'=>2,'D'=>3,'E'=>4,'F'=>5,'G'=>6,'H'=>7,'I'=>8,'J'=>9,'K'=>10,
			'L'=>11,'M'=>12,'N'=>13,'O'=>14,'P'=>15,'Q'=>16,'R'=>17,'S'=>18,'T'=>19,'U'=>20,
			'V'=>21,'W'=>22,'X'=>23,'Y'=>24,'Z'=>25,'a'=>26,'b'=>27,'c'=>28,'d'=>29,'e'=>30,
			'f'=>31,'g'=>32,'h'=>33,'i'=>34,'j'=>35,'k'=>36,'l'=>37,'m'=>38,'n'=>39,'o'=>40,
			'p'=>41,'q'=>42,'r'=>43,'s'=>44,'t'=>45,'u'=>46,'v'=>47,'w'=>48,'x'=>49,'y'=>50,
			'z'=>51,'0'=>52,'1'=>53,'2'=>54,'3'=>55,'4'=>56,'5'=>57,'6'=>58,'7'=>59,'8'=>60,
			'9'=>61,'!'=>62,'"'=>63,'%'=>64,'&'=>65,'\''=>66,'*'=>67,'+'=>68,'-'=>69,'.'=>70,
			'/'=>71,'_'=>72,','=>73,':'=>74,';'=>75,'='=>76,'<'=>77,'>'=>78,'?'=>79
		);
		$result+=pow(80, 3)*$s[$mrc[0]];
		$result+=pow(80, 2)*$s[$mrc[1]];
		$result+=pow(80, 1)*$s[$mrc[2]];
		$result+=pow(80, 0)*$s[$mrc[3]];
		return $result/100;
	}

	// Обработка кода маркировки для проверки в честном знаке
	function mark_for_chz($mark) {
		$len=mb_strlen($mark);
		$mrc=false;
		$expiration_date=0;
		if($len==29) { // Табак
			// первые 14 символов - GTIN-14, 0 + ean-13
			// следующие 7 символов - Серийный номер
			// следующие 4 символа - максимальная розничня цена
			// последние 4 символа - крипто-хвост
			$mrc=mb_substr($mark, 21, 4);
			$mrc=$this->mrc($mrc);
			$mark=mb_substr($mark, 0, 21);
		}
		elseif($len!=8
            && $len!=13
            && $len!=14
            && preg_match("/[A-Za-z0-9\/\\!”%&’()*+-.,:;=<>?]/", $mark)
            && mb_substr($mark, 0, 2)=='01'
            && mb_substr($mark, 16, 2)=='21') { //Лекарства или блок сигарет
			if(mb_substr($mark, 25, 4)=='8005') {
				$mrc=mb_substr($mark, 29, 6)/100;
			}

			$lp=true;
			$gtin=mb_substr($mark, 2, 14);

			$data=explode('', $mark);
			$serial=mb_substr($data[0], 18, 13);
			if($data[1]) {
				if(mb_substr($data[1], 0, 2)=='17') {
					$ed=str_split(mb_substr($data[1], 2, 6), 2);
					$expiration_date=strtotime(implode('-', $ed));
				}
				elseif(mb_substr($data[1], 0, 4)=='7003') {
					$ed=str_split(mb_substr($data[1], 4, 10), 2);
					$expiration_date=strtotime($ed[0].'-'.$ed[1].'-'.$ed[2].'T'.$ed[3].':'.$ed[4]);
				}
				elseif(mb_substr($data[1], 0, 4)=='8005') {
					$mrc=mb_substr($data[1], 4, 6)/100;
				}
			}
			
			$mark=$gtin.$serial;
		}
		return array(
			'code'=>$mark,
			'expiration_date'=>$expiration_date,
			'mrc'=>$mrc
		);
	}

	// Проверка статуса маркированного товара
	function check_mark_status($status) {
		if($status=='INTRODUCED') {
			return array(
				'success'=>true
			);
		}
		return array(
			'success'=>false,
			'txt'=>'labeling_code_not_entered_into_circulation'
		);
	}

	// Проверяем правильность составления дата матрикс
	function control_fnc($mark) {
		$len=mb_strlen($mark);
		if($len!=8
            && $len!=13
            && $len!=14
            && preg_match("/[A-Za-z0-9\/\\!”%&’()*+-.,:;=<>?]/", $mark)
            && mb_substr($mark, 0, 2)=='01'
            && mb_substr($mark, 16, 2)=='21') { // Значит дата маткрис
			if(mb_strpos($mark, '')===false && mb_strpos($mark, '\\u001d')===false) {
				$mark=''.mb_substr($mark, 0, 31).''.mb_substr($mark, 31, 6).''.mb_substr($mark, 37);
			}
		}
		return $mark;
	}

	// Девайсы
	function get_device() {
		$user_agents=array(
			'Platform: Android 5.0 (API 21)',
			'Platform: Android 5.0.1 (API 21)',
			'Platform: Android 5.0.2 (API 21)',
			'Platform: Android 5.1 (API 22)',
			'Platform: Android 5.1.1 (API 22)',
			'Platform: Android 6.0 (API 23)',
			'Platform: Android 6.0.1 (API 23)',
			'Platform: Android 7.0 (API 24)',
			'Platform: Android 7.1 (API 25)',
			'Platform: Android 7.1.1 (API 25)',
			'Platform: Android 7.1.2 (API 25)',
			'Platform: Android 8.0 (API 26)',
			'Platform: Android 8.1 (API 27)',
			'Platform: Android 9.0 (API 28)',
			'Platform: Android 10.0 (API 29)'
		);
		$devices=array(
			'samsung SM-J120F',
			'samsung SM-N930F',
			'samsung SM-N770F',
			'redmi M1908C3IG',
			'redmi M1901F7G',
			'redmi M1810F6LG',
			'huawei EVA-L09',
			'huawei AGS-l09',
			'huawei BG2-U01',
			'asus ZE554KL',
			'asus ZC554KL',
			'asus D541N'
		);
		return array(
			'user-agent'=>$user_agents[rand(0, count($user_agents)-1)],
			'device'=>$devices[rand(0, count($devices)-1)]
		);
	}

	function check_double_mark($mark) {
		$receiptlines=new \Models\Receiptlines($this->db, $this->f3);
		$lines=$receiptlines->select_lines(array('mark=?', array(json_encode(array($mark)))), array('limit'=>1));
		if($lines) {
			return array(
				'success'=>false,
				'txt'=>'marking_code_already_added',
			);
		}
		return array(
			'success'=>true
		);
	}

	// Проверяем маркировку через фр (ФФД 1.2)
	function check_mark_fr($mark, $count=1, $unit=0) {
		return $this->fr->check_mark($mark, (float)$count, $unit);
	}

	// Проверка кода маркировки через ЧЗ при разрешительной системе
	function check_mark_chz($sets, $line, $mark) {
		$chz=new \Models\Chz($this->db, $this->f3, $sets);
		return $chz->check_mark($line, $mark);
	}

	// Проверяем маркировку товара
	function check_mark($mark, $count=1, $unit=0, $check_chz=1) {
		$count=(float)$count;
		$mark=str_replace(' ', '+', $mark);
		if($check_chz==0 && $this->fr->sets['version']=='1.2') {
			$res=$this->check_mark_fr($mark, $count, $unit);
			$res['count']=$count;
			$res['error_type']='fr';
			return $res;
		}


		//$mark=str_replace('%26', '&', $mark);
		/*$check_double=$this->check_double_mark($mark);
		if(!$check_double['success']) {
			return $check_double;
		}*/
		// проверка дата матрикс
		$mark=$this->control_fnc($mark);
		$web=\Web::instance();
		$device=$this->get_device();
		$options = array(
			'method' => 'POST',
    		'follow_location' => 1,
    		'header'=>array(
    			'Content-Type: application/json; charset=UTF-8',
    			'user-agent: '.$device['user-agent'],
    			'Device: '.$device['device'],
    			'AppVersion: 4.5.3',
    			'AppVersionCode: 101'
    		),
    		'content'=>json_encode(array('code'=>$mark, 'codeType'=>'datamatrix')),
    		'timeout'=>3
		);
		$query='https://mobile.api.crpt.ru/mobile/check';
		$request=$web->request($query, $options);
		$json=json_decode($request['body'], true);
		if($json) {
			if($json[$json['category'].'Data']) {
				$data=$json[$json['category'].'Data'];
			}
			else {
				$data=$json;
			}
			$status=$data['status'];
			$check=$this->check_mark_status($status);
			if($check['success']) {
				$expiration_date=0;
				if($data['expirationDate']) {
					$expiration_date=strtotime($data['expirationDate']);
				}

				if($data['productProperty']['productWeightGr'] && ($unit==10 || $unit==11)) {
					$count=$data['productProperty']['productWeightGr'];
					if($unit==11) $count/=1000;
				}


				if($this->fr->sets['version']=='1.2') {
					$res=$this->check_mark_fr($mark, $count, $unit);
					$res['count']=(float)$count;
					if(!$res['success']) {
						$res['error_type']='fr';
						return $res;
					}
				}

				return array(
					'success'=>true,
					'code'=>$mark,
					'count'=>(float)$count,
					'expiration_date'=>$expiration_date
				);
			}
			else {
				return array(
					'success'=>false,
					'error_type'=>'chz',
					'count'=>(float)$count,
					'txt'=>$check['txt']
				);
			}
		}
		else {

			if($this->fr->sets['version']=='1.2') {
				$res=$this->check_mark_fr($mark, $count, $unit);
				$res['count']=(float)$count;
				if(!$res['success']) {
					$res['error_type']='fr';
				}
				return $res;
			}

			$error=$json['errorMessage'];
			if(!$error) {
				$error=json_decode($request['body'], true)['error_message'];
			}
			return array(
				'success'=>false,
				'error_type'=>'chz',
				'count'=>(float)$count,
				'txt'=>$error
			);
		}
		return array(
			'success'=>false,
			'error_type'=>'chz',
			'count'=>(float)$count,
			'txt'=>implode(';', $request)
		);
	}

	// Проверка товара ЕГАИС
	function check_egais($code, $line=array()) {
		/*if((int)$line['units']==796) {
			$check_double=$this->check_double_mark($code);
			if(!$check_double['success']) {
				return $check_double;
			}
		}*/

		return $this->egais->mark_check($code);
	}

	// Указываем, что оплата бонусами
	function bonus_pay($receipt) {
		if($receipt['partner']['bonus']>0 || $receipt['bonus_pay']>0) {
			if($receipt['bonus_pay']>0) {
				$bonus_pay=0;
			}
			elseif(isset($receipt['max_bonus_pay'])) {
				$bonus_pay=$receipt['max_bonus_pay'];
			}
			else {
				$bonus_pay=min(floor($receipt['sum']/100*$receipt['partner']['bonus_pay']), $receipt['partner']['bonus']);
			}
			$this->reset();
			$this->load(array('id=?', $receipt['id']), array('limit'=>1));
			if($this->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$this->bonus_pay=$bonus_pay;
			if($this->update()===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'close_all_window'=>true
			);
		}
		return array(
			'success'=>false,
			'txt'=>'no_bonus_to_pay'
		);
	}

	function add_correct($receipt, $lines, $type, $change, $fr=true) {
		$receipt['type']=$type;
		$receipt['user_id']=$this->f3->get('authorization_user.id');
		if($change) {
			$receipt['changes']=$change['id'];
			$receipt['changes_data']=json_encode($change);
		}
		if($fr) {
			$receipt['time']=microtime(true);
		}
		else {
			$receipt['time']=0;
		}
		$receipt['fd']='';
		$receipt['fp']='';
		$receipt['id']='';
		$receipt['slip']='';
		$receipt['egais_sign']='';

		$this->reset();
		$this->copyFrom($receipt);
		if($this->insert()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		$id=$this->get('_id');
		$receipt['id']=$id;

		if($fr) {
			foreach($lines as $n=>$l) {
				$lines[$n]['psr']=$receipt['psr'];
			}
			$fr_result=$this->fr->ticket($receipt, $lines, null, null, null, 1, null, null, null, null, null, null, $receipt['sno']);
			if(isset($fr_result['fd']) && isset($fr_result['fp'])) {
				$receipt['fd']=$fr_result['fd'];
				$receipt['fp']=$fr_result['fp'];
				$receipt['kkm_time']=$fr_result['kkm_time'];
				$receipt['fn']=$this->f3->get('fn');
				$this->copyFrom($receipt);
				$this->save();
			}
		}

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reroute'=>'/receipts/correct2?receipt_id='.$id.'&fpd='.$receipt['fpd'],
			'id'=>$id
		);
	}

	function set_turn($turns) {
		if(!$turns) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}
		$rl=new \Models\Receiptlines($this->db, $this->f3);
		foreach($turns as $line_id=>$turn) {
			$rl->load(array('id=?', $line_id), array('limit'=>1));
			if($rl->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$rl->turn=$turn;
			if($rl->update()===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
			$this->db->exec("UPDATE receiptlines SET turn=? WHERE parent_id=?", array($turn, $line_id));
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reload'=>array('.receiptlines'),
			'close_all_window'=>true
		);
	}

	function order_complite($id, $turn, $issued, $kitchen, $id_kitchen, $bar, $id_bar) {
		if($issued==1) {
			$sql="UPDATE receiptlines SET complite_order=?, issued_order=? WHERE receipt_id=? AND create_order>0 AND issued_order=0 AND turn=?";
			$val=array(microtime(true), microtime(true), $id, $turn);
		}
		else {
			$sql="UPDATE receiptlines SET complite_order=? WHERE receipt_id=? AND create_order>0 AND issued_order=0 AND turn=?";
			$val=array(microtime(true), $id, $turn);
		}
		$kitchen_where='';
		$bar_where='';
		if($kitchen==1) {
			if($id_kitchen>=0) {
				$kitchen_where='(kitchen=1 AND print_group_id=?) ';
				$val[]=$id_kitchen;
			}
			else {
				$kitchen_where=' (kitchen=1) ';
			}
		}
		if($bar==1) {
			if($id_bar>=0) {
				$bar_where='(bar=1 AND print_group_id=?)';
				$val[]=$id_bar;
			}
			else {
				$bar_where=' (bar=1) ';
			}
		}
		if($kitchen==1 && $bar==1) {
			$kitchen_where='('.$kitchen_where.' OR '.$bar_where.')';
			$bar_where='';
		}
		if($kitchen_where!='' || $bar_where!='') {
			$sql.=' AND '.$kitchen_where.$bar_where;
		}
		if($this->db->exec($sql, $val)===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'function'=>'reload_display()',
			'close_all_window'=>true
		);
	}

	function order_line_cancel_complite($id, $issued) {
		if($issued==1) {
			$sql="UPDATE receiptlines SET complite_order=?, issued_order=? WHERE (id=? OR parent_id=?) AND create_order>0 AND issued_order=0";
			$val=array(0, 0, $id, $id);
		}
		else {
			$sql="UPDATE receiptlines SET complite_order=? WHERE (id=? OR parent_id=?) AND create_order>0 AND issued_order=0";
			$val=array(0, $id, $id);
		}
		if($this->db->exec($sql, $val)===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'id'=>$id,
			'scroll'=>".receiptlines_div",
			'scrollto'=>"#line_".$id,
			'close_all_window'=>true
		);
	}

	function order_line_complite($id, $issued) {
		if($issued==1) {
			$sql="UPDATE receiptlines SET complite_order=?, issued_order=? WHERE (id=? OR parent_id=?) AND create_order>0 AND issued_order=0";
			$val=array(microtime(true), microtime(true), $id, $id);
		}
		else {
			$sql="UPDATE receiptlines SET complite_order=? WHERE (id=? OR parent_id=?) AND create_order>0 AND issued_order=0";
			$val=array(microtime(true), $id, $id);
		}
		if($this->db->exec($sql, $val)===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'function'=>'reload_display();',
			'close_all_window'=>true
		);
	}

	function other_order_complite($ip, $id, $turn, $issued, $kitchen, $id_kitchen, $bar, $id_bar) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query=$this->f3->get('SCHEME').'://'.$ip.'/receipts/order_complite?id='.$id.'&turn='.$turn.'&issued='.$issued.'&kitchen='.$kitchen.'&id_kitchen='.$id_kitchen.'&bar='.$bar.'&id_bar='.$id_bar;
		$json=$web->request($query, $options);
		if(mb_strpos($json['headers'][0], '200')!==false || mb_strpos($json['headers'][1], '200')!==false) {
			return json_decode($json['body'], true);
		}
		elseif(mb_strpos($json['headers'][0], '418')!==false || mb_strpos($json['headers'][1], '418')!==false) {
			return array(
				'success'=>418,
				'error'=>array('i_am_teapot'),
				'debug'=>array()
			);
		}
		else {
			return array(
				'success'=>false,
				'error'=>array('error'),
				'debug'=>array_merge($json['request'], $json['headers'], array($json['body'], $json['error']))
			);
		}
	}

	function other_order_line_cancel_complite($ip, $id, $issued) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query=$this->f3->get('SCHEME').'://'.$ip.'/receipts/order_line_cancel_complite?id='.$id.'&issued='.$issued;
		$json=$web->request($query, $options);
		if(mb_strpos($json['headers'][0], '200')!==false || mb_strpos($json['headers'][1], '200')!==false) {
			return json_decode($json['body'], true);
		}
		elseif(mb_strpos($json['headers'][0], '418')!==false || mb_strpos($json['headers'][1], '418')!==false) {
			return array(
				'success'=>418,
				'error'=>array('i_am_teapot'),
				'debug'=>array()
			);
		}
		else {
			return array(
				'success'=>false,
				'error'=>array('error'),
				'debug'=>array_merge($json['request'], $json['headers'], array($json['body'], $json['error']))
			);
		}
	}

	function other_order_line_complite($ip, $id, $issued) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query=$this->f3->get('SCHEME').'://'.$ip.'/receipts/order_line_complite?id='.$id.'&issued='.$issued;
		$json=$web->request($query, $options);
		if(mb_strpos($json['headers'][0], '200')!==false || mb_strpos($json['headers'][1], '200')!==false) {
			return json_decode($json['body'], true);
		}
		elseif(mb_strpos($json['headers'][0], '418')!==false || mb_strpos($json['headers'][1], '418')!==false) {
			return array(
				'success'=>418,
				'error'=>array('i_am_teapot'),
				'debug'=>array()
			);
		}
		else {
			return array(
				'success'=>false,
				'error'=>array('error'),
				'debug'=>array_merge($json['request'], $json['headers'], array($json['body'], $json['error']))
			);
		}
	}

	function issued_order($id, $turn, $kitchen, $id_kitchen, $bar, $id_bar) {
		$sql="UPDATE receiptlines SET issued_order=? WHERE receipt_id=? AND complite_order>0 AND issued_order=0 AND turn=?";
		$val=array(microtime(true), $id, $turn);
		$kitchen_where='';
		$bar_where='';
		if($kitchen==1) {
			if(is_numeric($id_kitchen) && $id_kitchen>=0) {
				$kitchen_where.='(kitchen=1 AND print_group_id=?) ';
				$val[]=$id_kitchen;
			}
			else {
				$kitchen_where='(kitchen=1)';
			}
		}
		if($bar==1) {
			if(is_numeric($id_bar) && $id_bar>=0) {
				$bar_where.='(bar=1 AND print_group_id=?)';
				$val[]=$id_bar;
			}
			else {
				$bar_where='(bar=1)';
			}
		}
		if($kitchen==1 && $bar==1) {
			$kitchen_where='('.$kitchen_where.' OR '.$bar_where.')';
			$bar_where='';
		}
		if($kitchen_where!='' || $bar_where!='') {
			$sql.=' AND '.$kitchen_where.$bar_where;
		}

		if($this->db->exec($sql, $val)===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'function'=>'reload_display()',
			'close_all_window'=>true
		);
	}

	function issued_order_line($id) {
		if($this->db->exec("UPDATE receiptlines SET issued_order=? WHERE (id=? OR parent_id=?) AND complite_order>0 AND issued_order=0", array(microtime(true), $id, $id))===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'function'=>'reload_display(); order_line_issued('.$id.')',
			'close_all_window'=>true
		);
	}

	function other_issued_order($ip, $id, $turn, $kitchen, $id_kitchen, $bar, $id_bar) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query=$this->f3->get('SCHEME').'://'.$ip.'/receipts/issued_order?id='.$id.'&turn='.$turn.'&kitchen='.$kitchen.'&id_kitchen='.$id_kitchen.'&bar='.$bar.'&id_bar='.$id_bar;
		$json=$web->request($query, $options);
		if(mb_strpos($json['headers'][0], '200')!==false || mb_strpos($json['headers'][1], '200')!==false) {
			return json_decode($json['body'], true);
		}
		elseif(mb_strpos($json['headers'][0], '418')!==false || mb_strpos($json['headers'][1], '418')!==false) {
			return array(
				'success'=>418,
				'error'=>array('i_am_teapot'),
				'debug'=>array()
			);
		}
		else {
			return array(
				'success'=>false,
				'error'=>array('error'),
				'debug'=>array_merge($json['request'], $json['headers'], array($json['body'], $json['error']))
			);
		}
	}

	function other_issued_order_line($ip, $id) {
		$web=\Web::instance();
		$options = array(
			'method' => 'GET',
    		'follow_location' => 1
		);
		$query=$this->f3->get('SCHEME').'://'.$ip.'/receipts/issued_order_line?id='.$id;
		$json=$web->request($query, $options);
		if(mb_strpos($json['headers'][0], '200')!==false || mb_strpos($json['headers'][1], '200')!==false) {
			return json_decode($json['body'], true);
		}
		elseif(mb_strpos($json['headers'][0], '418')!==false || mb_strpos($json['headers'][1], '418')!==false) {
			return array(
				'success'=>418,
				'error'=>array('i_am_teapot'),
				'debug'=>array()
			);
		}
		else {
			return array(
				'success'=>false,
				'error'=>array('error'),
				'debug'=>array_merge($json['request'], $json['headers'], array($json['body'], $json['error']))
			);
		}
	}

	function archive($time=0, $kitchen=1, $bar=1) {
		if($time==0) {
			$time=time();
		}

		$time0=strtotime(date('Y-m-d 00:00:00', $time));
		$time1=strtotime(date('Y-m-d 23:59:59', $time));

		$kitchen_where='';
		$bar_where='';
		if($kitchen==1) {
			$kitchen_where=' AND l.kitchen=1 ';
		}
		else {
			$kitchen_where=' AND l.kitchen=0 ';
		}
		if($bar==1) {
			$bar_where=' AND l.bar=1 ';
		}
		else {
			$bar_where=' AND l.bar=0 ';
		}
		if($kitchen==1 && $bar==1) {
			$kitchen_where=' AND (l.bar=1 OR l.kitchen=1)';
			$bar_where='';
		}
		$sql="SELECT l.*, r.order_number AS order_number FROM receiptlines AS l JOIN receipts AS r ON r.id=l.receipt_id WHERE l.create_order>=".$time0." AND l.create_order<=".$time1." ".$kitchen_where." ".$bar_where." ORDER BY l.create_order, l.turn";
		$receipts=$this->db->exec($sql);
		$result=array();
		if($receipts) {
			foreach($receipts as $r) {
				if($r['parent_id']>0) {
					$result[$r['order_number']][$r['turn']]['lines'][$r['parent_id']]['modifiers'][$r['id']]=$r;
				}
				else {
					$result[$r['order_number']][$r['turn']]['id']=$r['receipt_id'];
					$result[$r['order_number']][$r['turn']]['lines'][$r['id']]=$r;
					if($r['create_order']<$result[$r['order_number']][$r['turn']]['create_order'] || !$result[$r['order_number']][$r['turn']]['create_order']) {
						$result[$r['order_number']][$r['turn']]['create_order']=$r['create_order'];
					}

					if($r['complite_order']>$result[$r['order_number']][$r['turn']]['complite_order'] || !$result[$r['order_number']][$r['turn']]['complite_order']) {
						$result[$r['order_number']][$r['turn']]['complite_order']=$r['complite_order'];
					}

					if($r['issued_order']>$result[$r['order_number']][$r['turn']]['issued_order'] || !$result[$r['order_number']][$r['turn']]['issued_order']) {
						$result[$r['order_number']][$r['turn']]['issued_order']=$r['issued_order'];
					}
				}
			}
		}
		return $result;
	}

	function save_receipt($data) {
		$this->reset();
		if($data['id']) {
			$this->load(array('id=?', $data['id']), array('limit'=>1));
			if($this->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$id=$data['id'];
		}
		$this->copyFrom($data);
		if($this->save()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		if(!$id) {
			$id=$this->get('_id');
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'id'=>$id
		);
	}

	// Формируем ценник для печати
	function pricetags($product) {
		$this->fr->pricetags($product);
		return array(
			'success'=>true,
			'txt'=>'success',
			'close_all_window'=>true
		);
	}

	function print_qr($url) {
		return $this->fr->print_qr($url);
	}

	function paycontrol_qr($data) {
		$res=$this->fr->paycontrol_qr($data);
		if($res['success']===true) {
			$this->db->exec("UPDATE receipts SET slip=?, pan=?, authcode=?, transid=? WHERE id=?", array($res['slip'], $res['pan'], $res['authcode'], $res['transid'], $data['receipt_id']));
		}
		return $res;
	}

	// Методы электронной оплаты, использованные за смену
	function change_epays($change_id) {
		return $this->db->exec("SELECT DISTINCT(epay) AS epay FROM receipts WHERE changes=? AND time>0 AND epay>0", $change_id);
	}

	function combo_items($data) {
		$items=array();
		$product_id=array();
		if($data['items']) {
			foreach($data['items'] as $item) {
				$i=array();
				$i['title']=$item['title'];
				$i['price']=$item['price'];
				if($item['variants']) {
					foreach($item['variants'] as $variant) {
						if($variant['variant_type']=='product') {
							$i['variants'][]=$variant['product_id'];
							$product_id[]=$variant['product_id'];
						}
						else {
							$products=$this->db->exec("SELECT id FROM products WHERE date_delete=0 AND (stop=0 OR stop IS NULL) AND category_id=?", $variant['category_id']);
							if($products) {
								foreach($products as $p){
									$i['variants'][]=$p['id'];
									$product_id[]=$p['id'];
								}
							}
						}
					}
				}
				$items[]=$i;
			}
		}
		if($product_id) {
			$products=$this->db->exec("SELECT id, title, img FROM products WHERE id IN (".implode(', ', $product_id).") AND (stop=0 OR stop IS NULL) AND date_delete=0");
			$products=array_combine(array_column($products, 'id'), $products);
			foreach($items as $n=>$item){
				if($item['variants']) {
					foreach($item['variants'] as $vn=>$variant){
						if(isset($products[$variant]['img']) && $products[$variant]['img']!='' && $products[$variant]['img']!='null' && !is_array($products[$variant]['img'])) {
							$products[$variant]['img']=json_decode($products[$variant]['img'], true);
						}
						$items[$n]['variants'][$vn]=$products[$variant];
					}
				}
			}
		}
		return $items;
	}

	function split($sets, $receipt_id, $lines) {
		if(!$lines) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}

		$receipts=array();
		$rl=new \Models\Receiptlines($this->db, $this->f3);
		foreach($lines as $line_id=>$receipt_number) {
			if(empty($receipts)) {
				$receipts[$receipt_number]=$receipt_id;
			}
			elseif(!isset($receipts[$receipt_number])) {
				$res=$this->open_new($sets);
				if(!$res['success']) {
					return $res;
				}
				$receipts[$receipt_number]=$res['receipt_id'];
			}
			$rl->reset();
			$rl->load(array('id=?', $line_id), array('limit'=>1));
			if($rl->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$rl->receipt_id=$receipts[$receipt_number];
			if($rl->update()===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error'
				);
			}
			$this->db->exec("UPDATE receiptlines SET receipt_id=? WHERE parent_id=?", array($receipts[$receipt_number], $line_id));
		}

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'receipts'=>$receipts,
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'reload_menu'=>true,
			'close_all_window'=>true,
		);
	}

	function control_fn($res) {
		$fn_end=$this->f3->get('COOKIE.fn_end');
		$ofd_n=$this->f3->get('COOKIE.ofd_n');
		$er='';
		$now=time();
		if($fn_end>0) {
			$dn=round(($fn_end-$now)/(24*3600));
			if($dn>=0 && $dn<=7) {
				$error_txt='Срок ФН истекает '.(round(($fn_end-$now)/(24*3600))).' дн.';
				$er.='<p class=\'false\'>'.$error_txt.'</p>';
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)');
			}
			elseif($dn<=0) {
				$error_txt='Срок ФН истек';
				$er.='<p class=\'false\'>'.$error_txt.'</p>';
				$this->f3->get('logs_model')->save_log($error_txt.' (Касса)');
			}
		}
		if($ofd_n>=10) {
			$er.='<p class=\'false\'>Чеки не отправляются в ОФД. Ожидает отправки '.$ofd_n.'</p>';
			$error_txt='Чеки не отправляются в ОФД. Ожидает отправки '.$ofd_n;
			$er.='<p class=\'false\'>'.$error_txt.'</p>';
			$this->f3->get('logs_model')->save_log($error_txt.' (Касса)');
		}
		if($er) {
			$res['function']='show_window("error_fn","'.$er.'"); '.$res['function'];
		}
		$this->f3->set('COOKIE.fn_end', 0);
		$this->f3->set('COOKIE.ofd_n', 0);
		return $res;
	}

	function print_pricetags($printer, $lines, $count=1, $linesset_id=0, $title='', $print=1){
		$fr=new \Models\Fr($this->db, $this->f3, $printer, true);
		foreach($lines['lines'] as $l){
			$barcodes=json_decode($l['barcodes'], true);
			if(!$barcodes) {
				$barcodes=$this->db->exec("SELECT barcode FROM barcodes WHERE product_id=?", $l['product_id']);
			}
			if(!$barcodes) {
				$barcodes=array('');
			}
			$data=$l;
			$data['title']=$data['product_title'];
			$data['quantity']=$data['count'];
			unset($data['barcodes']);
			if($count>=1) {
				$end=$count;
			}
			else {
				$end=max(1, $l['stock']);
			}
			foreach ($barcodes as $b) {
				$data['barcodes'][0]['barcode']=$b;
				for($i=0; $i<$end; $i++) {
					$fr->pricetags($data);
				}
			}
		}
		return array(
			'success'=>true,
			'txt'=>'success'
		);
	}

	function print_linesset($printer, $lines, $count=1, $linesset_id=0, $title='', $print=1) {
		// [{"id":"1","title":"Название товара","price":"200.0","vat":"0","vat_type":"0","count":"2.0","mark":"qwewerqwer"}]
		$fr=new \Models\Fr($this->db, $this->f3, $printer, true);
		$val=array();
		$min=100000000000;
		foreach($lines['lines'] as $n=>$l){
			$mark=json_decode($l['mark'], true);
			$min=min($min, $l['count']);
			$val[$n]=array(
				'id'=>$l['product_id'],
				'title'=>$l['product_title'],
				'price'=>$l['price'],
				'vat'=>$l['vat'],
				'vat_type'=>$l['vat_type'],
				'count'=>$l['count']
			);
			if($mark) {
				$val[$n]['mark']=$mark[0];
			}
		}
		$json=json_encode($val);
		$lsm=new \Models\Linesset($this->db, $this->f3);
		$linesset=$lsm->save_linesset($json, $linesset_id, $title);
		if(!$linesset['success']) {
			return $linesset;
		}
		if($print) {
			$data=array(
				'title'=>$title,
				'vat'=>0,
				'vat_type'=>0,
				'price'=>number_format($lines['sum'], 2, '.', ''),
				'quantity'=>1,
				'barcodes'=>array(
					array('barcode'=>$linesset['barcode'])
				)
			);
			if($count>=1) {
				$end=$count;
			}
			else {
				$end=max(1, $min);
			}
			for($i=0; $i<$end; $i++) {
				$fr->pricetags($data);
			}
		}
		return array(
			'success'=>true,
			'txt'=>'success',
			'reroute'=>'/linesset/list'
		);
	}

	function printpricetags($lines, $data) {
		if(($data['print_type']!='linesset' && $data['print_type']!='pricetags') || !$lines) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}

		if(!$data['printer'] && $data['print_type']!='linesset') {
			return array(
				'success'=>false,
				'txt'=>'not_printers'
			);
		}

		$method='print_'.$data['print_type'];
		if($data['count_stock']) {
			$data['count']=-1;
		}

		return $this->$method($data['printer'], $lines, $data['count'], $data['linesset_id'], $data['title'], $data['print']);
	}

	function correction($data) {
		$fr_result=$this->fr->correction($data);
		if($fr_result['success']===true) {
			return array(
				'success'=>true,
				'txt'=>'save_successful'
			);
		}
		return array(
			'success'=>false,
			'txt'=>$fr_result['txt']
		);
	}

	// Документ подключения к крану
	function keg_connection($data, $change) {
		$receipt=array(
			'store'=>$data['store'],
			'rm'=>$data['rm'],
			'user_id'=>$this->f3->get('authorization_user.id'),
			'changes'=>$change['id'],
			'changes_data'=>json_encode($change),
			'time'=>microtime(true),
			'type'=>$data['type'],
			'payment'=>'',
			'sum'=>0,
			'client'=>'',
			'create_receipt'=>0,
			'description'=>''
		);

		$price=$data['product']['price'];
		if($data['product']['vat_type']>0) {
			$price=$price+round($price/100*$data['product']['vat'], 2);
		}

		$lines=array(
			array(
				'product_id'=>$data['product']['id'],
				'egais'=>2,
				'count'=>$data['volume'],
				'price'=>$price
			)
		);

		$egais=$this->egais->writeoff_v3(time(), $lines, 'Реализация');
		$receipt['egais_sign']=json_encode($egais);
		if(isset($egais['success']) && $egais['success']===false) {
			$egais['txt']=$egais['error'];
			return $egais;
		}

		$this->reset();
		$this->copyFrom($receipt);
		if($this->save()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		$id=$this->get('_id');

		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'id'=>$id,
			'close_all_window'=>true
		);
	}

	function salesreport($change_id) {
		$receipt_sales=$this->f3->get('receipt_sales');
		$receipt_return=$this->f3->get('receipt_return');
		$receipt_correct_sales=$this->f3->get('receipt_correct_sales');
		$receipt_correct_return=$this->f3->get('receipt_correct_return');
		$sql="SELECT l.product_id, l.product_title, SUM(l.count) AS total_count, SUM((CASE l.vat_type WHEN 1 THEN l.price+(l.price*(l.vat/100)) ELSE l.price END)*l.count) AS sum FROM receiptlines AS l WHERE l.create_order>0 AND l.complite_order>0 AND l.issued_order>0 AND l.receipt_id IN (SELECT r.id FROM receipts AS r WHERE r.time>0 AND r.changes=? AND r.type IN (".$receipt_sales.', '.$receipt_correct_sales.")) GROUP BY l.product_id";
		$val=array($change_id);
		$sales=$this->db->exec($sql, $val);
		$sales=array_combine(array_column($sales, 'product_id'), $sales);
		$sql="SELECT l.product_id, l.product_title, SUM(l.count) AS total_count, SUM((CASE l.vat_type WHEN 1 THEN l.price+(l.price*(l.vat/100)) ELSE l.price END)*l.count) AS sum FROM receiptlines AS l WHERE l.create_order>0 AND l.complite_order>0 AND l.issued_order>0 AND l.receipt_id IN (SELECT r.id FROM receipts AS r WHERE r.time>0 AND r.changes=? AND r.type IN (".$receipt_return.', '.$receipt_correct_return.")) GROUP BY l.product_id";
		$returns=$this->db->exec($sql, $val);
		$returns=array_combine(array_column($returns, 'product_id'), $returns);

		$result=array();
		foreach($sales as $product_id=>$s) {
			$result[$product_id]=$s;
			if(isset($returns[$product_id])) {
				$result[$product_id]['total_count']-=$returns[$product_id]['total_count'];
				$result[$product_id]['sum']-=$returns[$product_id]['sum'];
			}
		}
		foreach($returns as $product_id=>$r) {
			if(!isset($result[$product_id])) {
				$result[$product_id]=$r;
			}
		}

		return array(
			'sales'=>$sales,
			'returns'=>$returns,
			'correct_sales'=>$correct_sales,
			'correct_return'=>$correct_return,
			'result'=>$result
		);
	}

	function salesreport_print($lines) {
		$this->fr->salesreport_print($lines);
		return array(
			'success'=>true,
			'close_all_window'=>true
		);
	}

	function check_double_certificate($data) {
		$c=new \Models\Certificates($this->db, $this->f3);
		$c->load(array('product_id=? AND certificate=?', array($data['product_id'], $data['certificate'])), array('limit'=>1));
		if($c->dry()) return true;
		else return false;
	}

	function addcertificate($data) {
		$c=new \Models\Certificates($this->db, $this->f3);
		return $c->save_certificate($data);
	}

	function remove_certificate($data) {
		$c=new \Models\Certificates($this->db, $this->f3);
		return $c->remove_certificate($data);
	}

	function merge($receipts_id) {
		if(!$receipts_id || count($receipts_id)<2) {
			return array(
				'success'=>false,
				'txt'=>'min_2_for_merge'
			);
		}
		$in="?".str_repeat(', ?', count($receipts_id)-1);

		$count=$this->db->exec("SELECT COUNT(*) AS count FROM receipts WHERE id IN (".$in.") AND time=0 AND (type!=".$this->f3->get('receipt_print')." OR type IS NULL) AND user_id=".$this->f3->get('authorization_user.id'), $receipts_id);
		if($count[0]['count']!=count($receipts_id)) {
			return array(
				'success'=>false,
				'txt'=>'not_ready_tickets_for_merge'
			);
		}

		$receipt_id=$receipts_id[0];
		$val=$receipts_id;
		array_unshift($val, $receipt_id);
		$res=$this->db->exec("UPDATE receiptlines SET receipt_id=? WHERE receipt_id IN (".$in.")", $val);
		if($res) {
			$this->db->exec("DELETE FROM receipts WHERE id!=? AND id IN (".$in.")", $val);
			$this->reset();
			$this->load(array('id=?', $receipt_id), array('limit'=>1));
			$this->f3->set('COOKIE.receipt_id', $this->id);
			$this->f3->set('COOKIE.table_id', $this->table_id);
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines', '#receipts_buttons'),
				'function'=>'check_window_table()',
				'reload_menu'=>true,
				'close_all_window'=>true
			);
		}
		return array(
			'success'=>false,
			'txt'=>'db_error'
		);
	}
}
