<?php
namespace Models;

// Модель строк чека
class Receiptlines extends \DB\SQL\Mapper {
	public $db, $f3;
	public $marking_group=array(
		1=>array('title'=>'Предметы одежды, белье постельное, столовое, туалетное и кухонное', 'pg'=>'lp'),
		2=>array('title'=>'Обувные товары', 'pg'=>'shoes'),
		3=>array('title'=>'Табачные изделия', 'pg'=>'tobacco'),
		4=>array('title'=>'Духи и туалетная вода', 'pg'=>'perfumery'),
		5=>array('title'=>'Шины и покрышки пневматические резиновые новые', 'pg'=>'tires'),
		6=>array('title'=>'Фотокамеры (кроме кинокамер), фотовспышки и лампы-вспышки', 'pg'=>'electronics'),
		7=>array('title'=>'Лекарственные препараты для медицинского применения', 'pg'=>'pharma'),
		8=>array('title'=>'Молочная продукция', 'pg'=>'milk'),
		9=>array('title'=>'Велосипеды и велосипедные рамы', 'pg'=>'bicycle'),
		10=>array('title'=>'Кресла-коляски', 'pg'=>'wheelchairs'),
		11=>array('title'=>'Меховые изделия', 'pg'=>'furs'),
		12=>array('title'=>'Альтернативная табачная продукция', 'pg'=>'otp'),
		13=>array('title'=>'Питьевая вода', 'pg'=>'water'),
		14=>array('title'=>'Соковая продукция и безалкогольные напитки', 'pg'=>'beer'),
		15=>array('title'=>'Пиво', 'pg'=>'beer'),
		16=>array('title'=>'Разливное пиво', 'pg'=>'draftbeer'),
	);

	public function __construct($db, $f3) {
		parent::__construct($db, 'receiptlines'); // подключаемся к таблице строк чека
		$this->db=$db;
		$this->f3=$f3;
	}

	// Проверяем повтор марки
	function check_double_mark($mark, $receipt_id=0) {
		$mark=str_replace('', '\\u001d', $mark);
		$this->reset();
		$receipt_where='';
		$val=array('%"'.$mark.'"%');
		$line=$this->db->exec("SELECT r.type FROM receiptlines AS l JOIN receipts AS r ON r.id=l.receipt_id WHERE mark like ?  ORDER BY issued_order DESC LIMIT 1", $val);
		if(empty($line) || $line[0]['type']==$this->f3->get('receipt_return')) {
			return array(
				'success'=>true,
				'txt'=>'double_mark_not_found'
			);
		}
		return array(
			'success'=>false,
			'txt'=>'double_mark_found'
		);
	}

	// Выбираем строки из базы
	function select_lines($query, $option=null) {
		$products=new \Models\Products($this->db, $this->f3);
		$categories=new \DB\SQL\Mapper($this->db, 'productcategories');
		$barcodes=new \DB\SQL\Mapper($this->db, 'barcodes');
		$partners=new \DB\SQL\Mapper($this->db, 'partners');
		$lines=array();
		$parent=array();
		$modifiers=array();
		$sort_lines=array();
		$this->load($query, $option);
		if(!$this->dry()) {
			do {
				$l=$this->cast();
				$l['pg']='';
				$products->reset();
				$products->load(array('id=?', $l['product_id']), array('limit'=>1));
				if(!$products->dry()) {
					$product=$products->cast();
					$l['partner']=array();
					if($product['partner_id']>0) {
						$partners->load(array('partner_id=?', $product['partner_id']), array('limit'=>1));
						if(!$partners->dry()) {
							$l['partner']=$partners->cast();
							$l['partner']['type']=$product['partner_type'];
						}
					}
					if($product['marking_group']>0) {
						$l['pg']=$this->marking_group[$product['marking_group']]['pg'];
					}
					$l['img']=json_decode($product['img'], true);
					$l['max_discount']=$product['max_discount'];
					$l['print_group']=$product['print_group'];
					$l['marking']=$product['marking'];
					$l['marking_group']=$product['marking_group'];
					$l['quantity']=$product['quantity'];
					$l['cocktail']=$product['cocktail'];
					$l['egais']=$product['egais'];
					$l['category_id']=$product['category_id'];
					$l['ppr']=$product['ppr'];
					$l['print_group']=$product['print_group'];
					$l['add_bonus']=$product['add_bonus'];
					$l['stock']=$product['stock'];
					$l['stop']=$product['stop'];
					if(!$l['sno']) $l['sno']=$product['sno'];
					$l['code']=$product['code'];
					$l['multiple_sale']=$product['multiple_sale'];
					$barcodes->reset();
					$barcodes->load(array('product_id=?', $product['id']), array('limit'=>1));
					$l['barcode']=(string)$barcodes->barcode;
					$l['unit_okei']=$product['units']??0;
					$l['unit_short_title']=isset($products->units[$l['unit_okei']])?$products->units[$l['unit_okei']]['short_title']:'';
					$l['country_id']=$product['country_id'];
					$l['country_alpha2']=$product['country_alpha2'];
					$l['gtd']=$product['gtd'];
					$l['other']=json_decode($product['other_data'], true);
					// Если товар розливной, то остаток берем не из БД, а берем сумму остатков на кранах
					if($product['marking_group']==16) {
						$l['stock']=$products->spill_currentstock($l['product_id']);
					}
					$l['stock']-=$products->stock_openreceipts($l['product_id']);
				}
				else {
					$l['max_discount']=100;
					$l['print_group']=0;
					$l['egais']=0;
					$l['unit_okei']=0;
					$l['unit_short_title']='';
					$other_info=json_decode($l['other_info'], true);
					if($other_info) {
						$l['category_id']=$other_info['category_id'];
						$l['ppr']=$other_info['ppr'];
						$l['print_group']=$other_info['print_group'];
						$l['barcode']=$other_info['barcode'];
					}
				}
				if($l['category_id']) {
					$categories->reset();
					$categories->load(array('id=?', $l['category_id']), array('limit'=>1));
					if(!$categories->dry()) {
						$l['category_title']=$categories->title;
						$l['category_parent_id']=$categories->parent_id;
					}
				}

				$mark=json_decode($l['mark'], true);
				if(is_array($mark) && $l['egais']==1) {
					$l['mark_code']=array(
						'mark'=>$mark[0],
						'serial'=>mb_substr($mark[0], 3, 3),
						'number'=>mb_substr($mark[0], 6, 8),
					);
				}

				if($l['parent_id']>0) {
					$l['print_group']=$parent[$l['parent_id']]['print_group'];
					$modifiers[$l['parent_id']][]=$l;
				}
				else {
					$parent[$l['id']]=$l;
					$lines[]=$l;
				}
			}
			while($this->skip());
		}
		$this->reset();
		$kop=array();
		if($lines) {
			foreach ($lines as $l) {
				if($l['price']<0) {
					$kop=$l;
					continue;
				}
				$sort_lines[]=$l;
				if(isset($modifiers[$l['id']])) {
					$modifiers[$l['id']][array_key_last($modifiers[$l['id']])]['last']=1;
					$sort_lines=array_merge($sort_lines, $modifiers[$l['id']]);
					unset($modifiers[$l['id']]);
				}
			}
		}
		if($modifiers) {
			foreach ($modifiers as $m) {
				$sort_lines=array_merge($sort_lines, $m);
			}
		}
		if($kop) {
			$sort_lines[]=$kop;
		}
		return $sort_lines;
	}

	// Добавляем строку в чек
	function add_line($receipt_id, $line, $count=1, $parent_id=0, $create_order=null, $complite_order=null, $issued_order=null) {
		if(!is_numeric($count)) $count=(float)$line['quantity'];
		if($count<0) {
			return array(
				'success'=>false,
				'txt'=>'quantity_error'
			);
		}
		$line['parent_id']=$parent_id;
		if(!$line['turn']) $line['turn']=1;
		if($parent_id>0) {
			$this->load(array('id=?', $parent_id), array('limit'=>1));
			if($this->dry()) {
				return array(
					'success'=>true,
					'txt'=>'not_found',
					'function'=>'$(".modifiers_'.$line['product_id'].'").addClass("modifiers_count_1");'
				);
			}
			$line['kitchen']=$this->kitchen;
			$line['bar']=$this->bar;
			$line['print_group_id']=$this->print_group_id;
			$line['turn']=$this->turn;
			$line['create_order']=$this->create_order;
			$line['complite_order']=$this->complite_order;
			$line['issued_order']=$this->issued_order;
		}
		if(!isset($line['units_fr'])) $line['units_fr']=255;
		$line['receipt_id']=$receipt_id;
		$count=str_replace(',', '.', $count);
		$line['count']=abs(round($count, 3));
		$line['product_id']=$line['id'];
		if(!$line['product_title']) {
			$line['product_title']=$line['short_title'];
			if(!$line['product_title']) {
				$line['product_title']=$line['title'];
			}
		}
		$line['price']=str_replace(',', '.', $line['price']);
		$line['price']=abs($line['price']);
		if(!isset($line['price0'])) {
			$line['price0']=$line['price'];
		}
		if(!isset($line['discount'])) {
			$line['discount']=0;
		}
		if(!$line['loyalty']) {
			$line['loyalty']=0;
		}
		if(!$line['turn']) {
			$line['turn']=1;
		}
		if($create_order) {
			$line['create_order']=$create_order;
		}
		if($complite_order) {
			$line['complite_order']=$complite_order;
		}
		if($issued_order) {
			$line['issued_order']=$issued_order;
		}
		unset($line['id']);
		$this->reset();
		if($parent_id>0 && $line['mark']=='') {
			$this->load(array('product_id=? AND parent_id=?', array($line['product_id'], $parent_id)), array('limit'=>1));
			if($count==0) {
				return $this->delete_line($this->id);
			}
		}
		if(!is_numeric($line['price']) || $count<0) {
			return array(
				'success'=>false,
				'txt'=>'incorrect_data',
				'function'=>'$(".modifiers_false_'.$line['product_id'].'").addClass("modifiers_count_-1");'
			);
		}

		$line['price']=round($line['price'], 2);
		$line['price0']=round($line['price0'], 2);

		if($line['product_id']==null)$line['product_id']=0;
		$line['product_title']=html_entity_decode(html_entity_decode($line['product_title']));
		if(is_array($line['barcodes'])) $line['barcodes']=json_encode(array_column($line['barcodes'], 'barcode'));
		$this->copyFrom($line);

		if(!$this->add_time) $this->add_time=time();

		if($this->save()) {
			if($this->id) {
				$id=$this->id;
			}
			else {
				$id=$this->get('_id');
			}
			if($parent_id>0) {
				$scrollto='#line_'.$parent_id;
				$id=$parent_id;
				//$this->db->exec("UPDATE receiptlines SET bar=0, kitchen=0 WHERE id=? OR parent_id=?", array($parent_id, $parent_id));
			}
			else {
				$scrollto='#line_'.$id;
			}

			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'line'=>$line,
				//'reload'=>array('.receiptlines', '#receipts_buttons', '.button_total'),
				'reload'=>array('.receiptlines'),
				'id'=>$id,
				'scroll'=>'.receiptlines_div',
				'scrollto'=>$scrollto,
				'close_all_window'=>true,
				'function'=>'$(".modifiers_'.$line['product_id'].'").addClass("modifiers_count_1"); $(".free_title").val(""); $("#add_product_'.$line['product_id'].'").addClass("success_complete");'
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error',
				'function'=>'$(".modifiers_'.$line['product_id'].'").addClass("modifiers_count_-1");  $("#add_product_'.$line['product_id'].'").addClass("error_complete")'
			);
		}
	}

	// Счистаем сколько возвращено
	function count_return($id) {
		$count=$this->db->exec("SELECT SUM(l.count) AS count_return FROM receiptlines AS l JOIN receipts AS r ON r.id=l.receipt_id AND r.type=? AND r.time>0 WHERE l.line_parent_id=? AND l.create_order>0 AND l.complite_order>0 AND l.issued_order>0", array($this->f3->get('receipt_return'), $id));
		return $count[0]['count_return']??0;
	}

	// Меняем строку в чеке
	function change_line($line_id, $count, $price, $discount=0, $description=false, $loyalty=false, $writeoff_bonus=0) {
		$this->reset();
		$this->load(array('id=?', $line_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		if($this->parent_id==0 && ($this->kitchen>0 || $this->bar>0) && (isset($count) && $count!='' && $count!=$this->count)) {
			return array(
				'success'=>false,
				'txt'=>'position_is_already_in_progress'
			);
		}
		if($this->f3->get('receipt_type')!=$this->f3->get('receipt_writeoff')) {
			if($this->mark!='' && ($count && $count!=1) && $this->units_fr==0) {
				return array(
					'success'=>false,
					'txt'=>'quantity_marked_goods_may_not_exceed_1'
				);
			}
		}
		$line=$this->cast();
		if($count) {
			$count=str_replace(',', '.', $count);
			$line['count']=round($count, 3);
		}

		if($line['count']<=0) {
			return array(
				'success'=>false,
				'txt'=>'quantity_error_or_0'
			);
		}
		
		if(isset($price)) {
			$price=str_replace(',', '.', $price);
			if($line['vat_type']>0) {
				$price-=$price/(100+$line['vat'])*$line['vat'];
			}
			$line['price']=floatval($price);
		}
		$line['line_discount']=$discount;
		if(!$discount && $price && !$writeoff_bonus) {
			$line['price0']=$line['price'];
		}
		if($description!==false) {
			$line['description']=$description;
		}
		if($loyalty!==false) {
			$line['loyalty']=$loyalty;
		}
		$line['writeoff_bonus']=$writeoff_bonus;
		$this->copyFrom($line);
		if($this->update()) {
			if($line['parent_id']>0) {
				$val=array($line['parent_id'], $line['parent_id']);
			}
			else {
				$val=array($line['id'], $line['id']);
			}
			//$this->db->exec("UPDATE receiptlines SET bar=0, kitchen=0 WHERE id=? OR parent_id=?", $val);
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				//'reload'=>array('.receiptlines', '#receipts_buttons', '.button_total'),
				'reload'=>array('.receiptlines'),
				'scroll'=>'.receiptlines_div',
				'scrollto'=>'#line_'.$line_id,
				'id'=>$line_id,
				'line'=>$line,
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	// Удаляем строку из чека
	function delete_line($line_id, $receipt=null) {
		$this->reset();
		$return_bonus=0;
		$deleted=array();
		if($line_id=='all') {
			if($receipt) {
				$receipt_id=$receipt['id'];
				if($receipt['partner_id']>0) {
					$res=$this->db->exec('SELECT SUM(writeoff_bonus) as return_bonus FROM receiptlines WHERE receipt_id=?', $receipt_id);
					if($res[0]['return_bonus']>0)$return_bonus=$res[0]['return_bonus'];
				}
			}
			else {
				$receipt_id=$this->f3->get('COOKIE.receipt_id');
			}
			$deleted=$this->db->exec('SELECT * FROM receiptlines WHERE receipt_id=?', $receipt_id);
			$res=$this->db->exec("DELETE FROM `receiptlines` WHERE `receipt_id`=?", $receipt_id);
			if($res===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error',
				);
			}
		}
		else {
			$this->load(array('id=?', $line_id), array('limit'=>1));
			if($this->dry()) {
				return array(
					'success'=>false,
					'txt'=>'not_found'
				);
			}
			$line=$this->cast();

			if($receipt['partner_id']>0) {
				$return_bonus=$line['writeoff_bonus'];
			}

			if($this->combo_id>0) {
				$combo_lines=$this->db->exec("SELECT * FROM receiptlines WHERE combo_id=?", $this->combo_id);
			}
			else {
				$deleted[]=$line;
			}

			if($this->erase(array('id=? OR parent_id=? OR (combo_id>0 AND combo_id=?)', array($line_id, $line_id, $this->combo_id)))===false) {
				return array(
					'success'=>false,
					'txt'=>'db_error',
					'function'=>'$(".modifiers_'.$line['product_id'].'").addClass("modifiers_count_-1");'
				);
			}
		}
		if($combo_lines) {
			foreach($combo_lines as $l) {
				$deleted[]=$l;
			}
			$this->erase(array('parent_id IN ('.implode(', ', array_column($combo_lines, 'id')).')'));
		}
		if($return_bonus>0) {
			$this->db->exec("UPDATE partners SET bonus=bonus+? WHERE partner_id=?", array($return_bonus, $receipt['partner_id']));
		}
		if(!empty($deleted)) {
			foreach($deleted as $n=>$d) {
				$other_info=json_decode($d['other_info'], true);
				if(!is_array($other_info)) {
					$other_info=array();
				}
				$other_info['time_delete']=time();
				$deleted[$n]['other_info']=json_encode($other_info);
			}
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			//'reload'=>array('.receiptlines', '#receipts_buttons', '.button_total'),
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'line'=>$line,
			'deleted'=>$deleted,
			'close_all_window'=>true
		);
	}

	// Узнаем сумму строк
	function get_sum($lines, $discount=0, $round_kop=0, $bonus_pay=0, $ignore_max_discount=0) {
		$sum=0;
		$sum0=0;
		$receipt_id=0;
		if(!$lines) {
			return 0;
		}

		$beers=array();
		foreach($lines as $ln=>$l) {
			if($l['pg']=='draftbeer' && $l['mark']!='') {
				$l['sum']=$l['price']*$l['count'];
				$mark=json_decode($l['mark'], true)[0];
				if(!isset($beers[$mark])) {
					$tap=$this->db->exec("SELECT * FROM taps WHERE mark=? LIMIT 1", $mark);
					if(!empty($tap) && $tap[0]['product_title']!='') {
						$l['product_title']=$tap[0]['product_title'];
					}
					$beers[$mark]=$l;
				}
				else {
					$beers[$mark]['count']+=$l['count'];
					$beers[$mark]['sum']+=$l['sum'];
				}
				unset($lines[$ln]);
			}
		}

		if(!empty($beers)) {
			foreach($beers as $b) {
				$b['price']=round($b['sum']/$b['count'], 2);
				$lines[]=$b;
			}
		}

		if($bonus_pay>0) {
			$lines_bonus=$this->lines_price_bonus_pay($lines, $bonus_pay, $ignore_max_discount);
			$lines=$lines_bonus['lines'];
		}

		foreach ($lines as $key=>$l) {
			if($ignore_max_discount) {
				$l['max_discount']=100;
			}
			if($round_kop==1 && $l['loyalty']==3) continue;
			if($receipt_id==0) {
				$receipt_id=$l['receipt_id'];
			}
			$s=round($l['price']+($l['price']*(($l['vat']/100)*max(0, $l['vat_type']))), 2);
			if(!$l['loyalty']) {
				if((float)$l['discount']) {
					$s-=round($s*($l['discount']/100), 2);
				}
				else {
					if($discount) {
						if($discount<$l['max_discount']) {
							$s-=round($s*($discount/100), 2);
						}
						else {
							$s-=round($s*($l['max_discount']/100), 2);
						}
					}
				}
			}

			$lines[$key]['discount_sum']=$lines[$key]['price']-$s;
			$lines[$key]['price']=round($s, 2);
			$s=round($lines[$key]['price']*$l['count'], 2);
			$sum+=$s;
		}

		$d_sum=$sum-floor($sum);
		if((int)$round_kop==1) {
			$this->delete_kop($receipt_id, $d_sum);
			$sum=floor($sum);
		}

		$sum=round($sum, 2);
		return array(
			'sum'=>$sum,
			'lines'=>$lines
		);
	}

	// Отбрасываем копейки
	function delete_kop($receipt_id, $kop) {
		$this->reset();
		$this->load(array('receipt_id=? AND loyalty=3', $receipt_id), array('limit'=>1));
		if($kop==0) {
			$this->erase();
			return;
		}
		$data=array(
			'receipt_id'=>$receipt_id,
			'product_id'=>0,
			'product_title'=>'Отбрасывание копеек',
			'price'=>-$kop,
			'price0'=>-$kop,
			'discount'=>0,
			'line_discount'=>0,
			'vat'=>0,
			'vat_type'=>0,
			'count'=>1,
			'description'=>'Отбрасывание копеек',
			'loyalty'=>3,
		);
		$this->copyFrom($data);
		$this->save();
	}

	// Отмечаем, что позиция была напечатана на принтере кухни или бара
	function print_ok($line_id, $printer, $device=0) {
		$this->reset();
		$this->load(array('id=?', $line_id), array('limit'=>1));
		if($this->dry()) {
			return false;
		}
		$data[$printer]=1;
		if($printer=='kitchen' || $printer=='bar') {
			$data['create_order']=microtime(true);
			if((int)$device==1) {
				$data['complite_order']=microtime(true);
				$data['issued_order']=microtime(true);
			}
		}
		$this->copyFrom($data);
		if($this->update()===false) {
			return false;
		}
		return true;
	}

	// Выдаем то что не надо отправлять на кухню или бар
	function issued_receipt($receipt_id, $all=0) {
		$where_product='';
		if($all==0) {
			$where_product=' AND ((bar=0 AND kitchen=0) OR product_id<0) ';
		}
		$this->db->exec("UPDATE `receiptlines` SET `create_order`=(case create_order when 0 then ? else create_order end), `complite_order`=(case complite_order when 0 then ? else complite_order end), `issued_order`=(case issued_order when 0 then ? else issued_order end) WHERE `receipt_id`=? ".$where_product, array(microtime(true), microtime(true), microtime(true), $receipt_id));
	}

	// Сохраняем строки в базе данных
	function save_lines($receipt, $discount=0, $create_order=null, $complite_order=null, $issued_order=null, $device=false) {
		if($create_order===null) $create_order=microtime(true);
		if($complite_order===null) $complite_order=microtime(true);
		if($issued_order===null) $issued_order=microtime(true);
		if(!$receipt['id']) {
			return array(
				'success'=>false,
				'txt'=>'not_enough_data'
			);
		}

		$device_where='';

		if($device=='kitchen' || $device=='bar') {
			$device_where=' AND '.$device.'=1 ';
		}
		elseif($device=='remaining') {
			$device_where=' AND kitchen=0 AND bar=0 ';
		}
		if($discount!=0) {
			$lines=$this->select_lines(array('receipt_id=? AND loyalty=0'.$device_where, $receipt['id']));
			if($lines) {
				foreach ($lines as $l) {
					if($l['max_discount']<$discount) {
						$d=$l['max_discount'];
					}
					else {
						$d=$discount;
					}
					if($receipt['partner']['ignore_max_discount']>0) {
						$d=$discount;
					}
					if($d) {
						if($receipt['client'] || $receipt['partner_id']) {
							$description='Скидка клиента';
						}
						else {
							$description='Скидка на чек';
						}
					}
					else {
						$description='';
					}
					$res=$this->db->exec("UPDATE `receiptlines` SET `discount`=?, `description`=? WHERE `id`=?", array($d, $description, $l['id']));
					if($res===false) break;
				}
			}
		}

		$res=$this->db->exec("UPDATE `receiptlines` SET `create_order`=(case create_order when 0 then ? else create_order end), `complite_order`=(case complite_order when 0 then ? else complite_order end), `issued_order`=(case issued_order when 0 then ? else issued_order end) WHERE `receipt_id`=?".$device_where, array($create_order, $complite_order, $issued_order, $receipt['id']));
		if($res===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			//'reload'=>array('.receiptlines', '#receipts_buttons', '.button_total'),
			'reload'=>array('.receiptlines', '#receipts_buttons'),
			'reload_menu'=>true,
			'close_all_window'=>true
		);
	}

	// Применение программ лояльности
	function apply_loyalty($receipt, $product, $loyalty, $all=false) {
		$res=$this->db->exec("SELECT SUM(count) AS count FROM `receiptlines` WHERE receipt_id=? AND product_id=? AND loyalty!=2", array($receipt['id'], $product['id']));
		$count=$res[0]['count']; // Общее кол-во товара
		if($all==true) {
			$lines=$this->select_lines(array('receipt_id=? AND product_id=? AND loyalty!=2', array($receipt['id'], $product['id'])), array('order'=>'count'));
		}
		else {
			$lines=$this->select_lines(array('receipt_id=? AND product_id=? AND loyalty=0', array($receipt['id'], $product['id'])), array('order'=>'count'));
		}
		$selected=array(); // Выбранная программа
		// Если программ несколько, то перебираем программы лояльности, что бы узнать самую выгодную
		$new_price=false;
		foreach ($loyalty as $n => $l) {
			$items=json_decode($l['data'], true);
			// Находим параметры программы лояльности для товара
			$l_data=array();

			if($l['action_type']>0) {

				if(isset($items['product'][$product['id']])) { // Если параметры указаны для товара
					$l_data=$items['product'][$product['id']];
				}
				else { // Если параметры указаны для категории
					if(isset($items['category'][$product['category_id']])) {
						$l_data=$items['category'][$product['category_id']];
					}
				}
			}
			elseif($l['action_type']<0 && (is_array($items['product']) || is_array($items['category']))) {
				if(!isset($items['product'][$product['id']]) && !isset($items['category'][$product['category_id']])) { // Если параметры указаны для товара
					$l_data=$items['product'][array_key_first($items['product'])];
				}
				else { // Если параметры указаны для категории
					if(!isset($items['category'][$product['category_id']])) {
						$l_data=$items['category'][array_key_first($items['category'])];
					}
				}
			}
			// Если параметры нашлись, вычисляем новую цену
			if($l_data) {
				if($l_data['quantity']=='')$l_data['quantity']=0;
				// Если кол-во товара соответствует необходимому
				if(($l_data['quantity_type']=='>' && $count>$l_data['quantity']) || ($l_data['quantity_type']=='=' && $count>=$l_data['quantity']) || ($l_data['quantity_type']=='+' && $count>$l_data['quantity']) || (isset($receipt['sum']) && $l_data['quantity_type']=='receiptsumm' && $receipt['sum']>$l_data['quantity'])) {
					// Цена с учетом НДС, но без учета скидки
					$price=$product['price']+($product['price']/100*$product['vat'])*max(0, $product['vat_type']);
					// Вычисляем цену со скидкой, с учетом типа скидки
					if($l_data['discount_type']=='opt_price_1' || $l_data['discount_type']=='opt_price_2' || $l_data['discount_type']=='opt_price_3') {
						$price=$product[$l_data['discount_type']]!=0?$product[$l_data['discount_type']]:$product['price'];
					}
					elseif($l_data['discount_type']=='%') {
						$l_discount=$l_data['discount'];
						if($l_discount>$product['max_discount'] && (int)$l['ignor_maxdiscount']===0) {
							$l_discount=$product['max_discount'];
						}
						$price-=($price/100*$l_discount);
					}
					elseif($l_data['discount_type']=='='){
						$price=$l_data['discount'];
					}
					else {
						$price-=$l_data['discount'];
					}

					if($product['mrp']>0 && $price>$product['mrp']/100 && $product['marking_group']!=30) {
						$price=$product['mrp']/100;
					}
					if($product['smp']>0 && $price<$product['smp']/100) {
						$price=$product['smp']/100;
					}

					// Если нашли более выгодную программу
					if($new_price===false || $new_price>$price) {
						$new_price=$price;
						$selected=$l;
						$selected['data']=$l_data;
					}
				}
			}
		}
		// Применяем программу лояльности
		if($selected['data']['discount_type']=='%') {
			$discount=$selected['data']['discount'];
		}
		else {
			$discount=0;
		}

		if($discount>$product['max_discount'] && (int)$l['ignor_maxdiscount']===0) {
			$discount=$product['max_discount'];
		}

		$not_discount=$selected['data']['quantity']; // Кол-во к которому не надо применять скидку
		if($selected['data']['quantity_type']=='=') { // Если скидка на определенное кол-во
			$not_discount=$count%$not_discount;
		}

		if($selected['data']['quantity_type']=='+' || $selected['data']['quantity_type']=='receiptsumm') {
			$not_discount=0;
		}

		// Если нужно применить не ко всему кол-ву
		if($not_discount>0) {
			// Ищем строку у которой указано кол-во, к которому не нужно применять скидку, а вдруг такая есть
			$l_key=array_search($not_discount, array_column($lines, 'count'));
			if($l_key!==false) {
				// если такая строка нашлась, то удаляем ее, и применем скидку к оставшимся строкам
				unset($lines[$l_key]);
			}
			else {
				// Если такой строки нет, то надо работать с тем, что есть
				foreach ($lines as $n=>$l) {
					if($l['count']<=$not_discount) {
						$not_discount-=$l['count'];
						unset($lines[$n]);
					}
					elseif($not_discount>0) {
						// Если кол-во больше необходимого, то придется кол-во разделить на 2 строки
						// Оставляем в строке то кол-во, к которому будет применена скидку
						$lines[$n]['count']-=$not_discount;
						// Создаем новую строку с тем кол-вом, к которому не надо применять скидку
						$line=array(
							'id'=>$l['product_id'],
							'title'=>$l['product_title'],
							'price'=>$product['price'],
							'price0'=>$product['price'],
							'vat'=>$l['vat'],
							'vat_type'=>$l['vat_type']
						);
						$this->add_line($receipt['id'], $line, $not_discount);
						break;
					}
				}
			}
		}
		// Применяем скидку
		if($lines && $selected) {
			foreach ($lines as $l) {
				$l['price']=$new_price;
				$l['discount']=$discount;
				$l['description']='Акция: '.$selected['title'];
				$l['loyalty']=1;
				$l['loyalty_id']=$selected['id'];
				$this->save_line($l);
				//$this->change_line($l['id'], $l['count'], $new_price, $discount, 'Акция: '.$selected['title'], 1);
			}
		}
	}

	function save_line($data) {
		$this->load(array('id=?', $data['id']), array('limit'=>1));
		$data['price']=round($data['price'], 2);
		$data['price0']=round($data['price0'], 2);
		$this->copyFrom($data);
		if($this->update()) {
			return array(
				'success'=>true,
				'txt'=>'save_successful',
				'reload'=>array('.receiptlines'),
				'scroll'=>'.receiptlines_div',
				'scrollto'=>'#line_'.$line_id,
				'line'=>$data,
				'close_all_window'=>true
			);
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
	}

	function apply_auto_add_loyalty($receipt, $loyalty) {
		foreach ($loyalty as $n => $l) {
			$items=json_decode($l['data'], true);
			// Находим параметры программы лояльности для товара
			$l_data=array();

			if(isset($items['product'])) {
				foreach($items['product'] as $item) {
					if($item['quantity_type']!='add') continue;
					$product=$this->db->exec("SELECT * FROM products WHERE id=? AND date_delete=0 LIMIT 1", $item['product_id']);
					if($product) {
						$min_price=0;
						if((int)$l['ignor_maxdiscount']===0) {
							$min_price=round($product[0]['price']/100*$product[0]['max_discount'], 2);
						}
						if($item['discount_type']=='=') $product[0]['price']=$item['discount'];
						elseif($item['discount_type']=='%') $product[0]['price']-=round($product[0]['price']/100*$item['discount'], 2);
						else $product[0]['price']-=$item['discount'];
						if($product[0]['price']<$min_price) $product[0]['price']=$min_price;
						$product[0]['price']=round($product[0]['price'], 2);
						$product[0]['price0']=round($product[0]['price0'], 2);
						$product[0]['description']='Акция: '.$l['title'];
						$product[0]['loyalty']=4;
						$this->add_line($receipt['id'], $product[0], $item['quantity']);
					}
				}
			}

			if(isset($items['category'])) {
				foreach($items['category'] as $item) {
					if($item['quantity_type']!='add') continue;
					$products=$this->db->exec("SELECT * FROM products WHERE category_id=? AND date_delete=0", $item['category_id']);
					if($products) {
						foreach ($products as $product) {
							$min_price=0;
							if((int)$l['ignor_maxdiscount']===0) {
								$min_price=round($product['price']/100*$product['max_discount'], 2);
							}
							if($item['discount_type']=='=') $product['price']=$item['discount'];
							elseif($item['discount_type']=='%') $product['price']-=round($product['price']/100*$item['discount'], 2);
							else $product['price']-=$item['discount'];
							if($product['price']<$min_price) $product['price']=$min_price;
							$product['price']=round($product['price'], 2);
							$product['price0']=round($product['price0'], 2);
							$product['description']='Акция: '.$l['title'];
							$product['loyalty']=4;
							$this->add_line($receipt['id'], $product, $item['quantity']);
						}
					}
				}
			}
		}
	}

	function cancel_auto_add_loyalty($receipt) {
		$this->erase(array('loyalty=4 AND receipt_id=?', $receipt['id']));
	}

	function linesmerge($line_id) {
		$this->reset();
		$this->load(array('id=? AND kitchen=0 AND bar=0', $line_id), array('limit'=>1));
		if($this->dry()) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$lines=$this->db->exec("SELECT * FROM receiptlines WHERE receipt_id=? AND product_id=? AND vat=? AND vat_type=? AND price=? AND price0=? AND discount=? AND (mark='' OR  mark IS NULL) AND units_fr>=0 AND id!=? AND kitchen=0 AND bar=0", array($this->receipt_id, $this->product_id, $this->vat, $this->vat_type, $this->price, $this->price0, $this->discount, $line_id));
		if(!$lines) {
			return array(
				'success'=>true,
				'txt'=>'save_successful'
			);
		}

		foreach($lines as $n=>$l) {
			$mod=$this->db->exec("SELECT COUNT(*) AS mod_count FROM receiptlines WHERE parent_id=?", $l['id']);
			if($mod[0]['mod_count']>0) {
				unset($lines[$n]);
			}
		}

		if(!$lines) {
			return array(
				'success'=>true,
				'txt'=>'save_successful'
			);
		}

		$count=array_sum(array_column($lines, 'count'));

		$this->count+=$count;
		if($this->update()) {
			$this->db->exec("DELETE FROM receiptlines WHERE id IN (".implode(',', array_column($lines, 'id')).")");
			return array(
				'success'=>true,
				'txt'=>'save_successful'
			);
		}

		return array(
			'success'=>false,
			'txt'=>'db_error'
		);
	}

	// Отмена акций
	function cancel_loyalty($receipt, $product) {
		$sql="UPDATE `receiptlines` SET `price`=?, `loyalty`=0, `line_discount`=0, `discount`=0, `description`='' WHERE `receipt_id`=? AND `product_id`=? AND `loyalty`>0 AND `loyalty`!=2 AND `loyalty`!=3";
		$val=array(
			$product['price'],
			$receipt['id'],
			$product['id']
		);
		$this->db->exec($sql, $val);
	}

	function max_bonus_pay($summ, $partner, $lines) {
		if(!$lines) return 0;
		if($partner['loyalty_type']==2) {
			foreach($lines as $n=>$l){
				$lines[$n]['max_discount']=min($l['max_discount'], $partner['bonus_pay']);
				if($partner['ignore_max_discount']==1) {
					$lines[$n]['max_discount']=$partner['bonus_pay'];
				}
				else {
					$lines[$n]['max_discount']=min($l['max_discount'], $partner['bonus_pay']);
				}
			}
		}
		$res=$this->lines_price_bonus_pay($lines, $partner['bonus'], 0);
		$bonus_pay=round(array_sum(array_column($res['lines'], 'bonus_pay')));
		return $bonus_pay;
	}

	function lines_price_bonus_pay($lines, $bonus_pay, $ignore_max_discount=0) {
		// Вычисляем цену с учетом оплаты баллами
		$bonus_pay0=$bonus_pay;
		while ($bonus_pay>0) {
			foreach ($lines as $key=>$l) {
				if($l['loyalty']>0) continue;
				if(!$l['max_b']) {
					if($ignore_max_discount==1) $l['max_discount']=100;
					$l['sum']=round($l['price0']*$l['count'], 2);
					//$l['max_b']=floor($l['price0']/100*$l['max_discount']*100)/100;
					$l['max_b']=floor($l['sum']/100*$l['max_discount']);
					$lines[$key]['max_b']=$l['max_b'];
					$l['bonus_pay']=0;
					$lines[$key]['bonus_pay']=0;
				}
				if($bonus_pay>=1) {
					$b=round(1/$l['count'], 2);
				}
				else {
					break(2);
				}
				if($l['bonus_pay_max']==1) {
					continue;
				}
				//elseif($b>$l['price'] || $l['price0']-($l['price']-$b)>$l['max_b']) {
				elseif($b>$l['price'] || $l['bonus_pay']+$b*$l['count']>$l['max_b']) {
					$lines[$key]['bonus_pay_max']=1;
					continue;
				}
				//$b=round($b, 2);
				$lines[$key]['price']-=$b;
				$lines[$key]['price']=round($lines[$key]['price'], 2);
				$b=$b*$l['count'];
				$lines[$key]['bonus_pay']+=$b;
				$bonus_pay=$bonus_pay-$b;
			}
			if($bonus_pay0!=$bonus_pay) {
				$bonus_pay0=$bonus_pay;
			}
			else {
				break;
			}
		}

		// Если остались копеечные бонусы, то надо разделить строки
		// Если осталось много бонусов, больше 1, это из-за того что не все бонусы можно потратить, потому что есть ограничения по оплате бонусами
		if($bonus_pay>0 && $bonus_pay<=1) { // Именно копеечные бонусы
			foreach($lines as $key=>$l) {
				if($l['loyalty']>0) continue;
				if($l['count']>1 && $l['price']>$bonus_pay) {
					$bp=$l['bonus_pay']/$l['count'];
					$lines[$key]['count']-=1;
					$lines[$key]['bonus_pay']=$bp*$lines[$key]['count'];

					$new_line=$l;
					unset($new_line['id']);
					$new_line['count']=1;
					$new_line['price']-=$bonus_pay;
					$new_line['bonus_pay']=round($bp+$bonus_pay, 2);
					$lines[]=$new_line;
					$bonus_pay=0;
					break;
				}
			}
		}

		$total=0;
		foreach($lines as $l){
			$total+=$l['count']*$l['price'];
		}

		return array(
			'lines'=>$lines,
			'bonus_pay'=>$bonus_pay,
			'total'=>$total
		);
	}

	function lines_bonus_pay($lines, $bonus_pay, $ignore_max_discount=0) {
		$res=$this->lines_price_bonus_pay($lines, $bonus_pay, $ignore_max_discount);
		foreach ($res['lines'] as $l) {
			if($l['loyalty']>0) continue;
			$this->reset();
			if(isset($l['id'])) {
				$this->load(array('id=?', $l['id']), array('limit'=>1));
			}
			$l['description']='Оплачено баллами';
			$l['bonus_pay']=number_format($l['bonus_pay'], 2, '.', '');
			$l['writeoff_bonus']=$l['bonus_pay'];
			$this->copyFrom($l);
			$this->save();
		}
		return; 
	}

	function insert_line($line) {
		$this->reset();
		$this->copyFrom($line);
		if($this->insert()===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}
		return array(
			'success'=>true,
			'txt'=>'save_successful',
			'id'=>$this->get('_id')
		);
	}

	function control_sno($lines, $sno_default, $sno_types=array()) {
		if(!$lines) return true;
		$sno=array();
		$sno_status=true;
		foreach($lines as $l) {
			if($l['sno']=='0' || !$l['sno'])$l['sno']=$sno_default;
			$sno[(string)$l['sno']]=1;
			if($sno_types && !in_array($l['sno'], $sno_types)) {
				$sno_status=false;
			}
		}
		if(count($sno)<=1) $status=true;
		else $status=false;
		return array(
			'status'=>$status,
			'sno'=>array_keys($sno),
			'sno_status'=>$sno_status
		);
	}

	// Проверяем марку ЕГАИС
	function check_egais_mark ($mark_code, $count, $product, $component=0) {
		// Ищем марку в БД
		if(isset($product['unit_okei'])) {
			$product['units']=$product['unit_okei'];
			$product['id']=$product['product_id'];
		}
		$mark=$this->db->exec("SELECT m.*, p.cocktail FROM egais_marks AS m JOIN products AS p ON p.id=m.product_id WHERE m.mark=? LIMIT 1", $mark_code);
		if(!$mark) {
			return array(
				'success'=>false,
				'txt'=>'products_did_not_pass_inspection'
			);
		}
		if($mark[0]['chpok']==1 && (int)$product['units']==796 && $component==0) {
			return array(
				'success'=>false,
				'txt'=>'bottle_is_open'
			);
		}

		if($mark[0]['product_id']!=$product['id']) {
			$error=true;
			
			if($mark[0]['cocktail']!='') {
				$components=json_decode($mark[0]['cocktail'], true);
				$components=array_column($components, 'product_id');
				if(in_array($product['id'], $components)) {
					$error=false;
				}
			}
			
			if($error) {
				return array(
					'success'=>false,
					'txt'=>'mark_from_other_product'
				);
			}
		}
		$add_volume=0;
		if((int)$product['units']==796) {
			$add_volume=$count*$mark[0]['capacity']*1000;
		}
		elseif((int)$product['units']==112) {
			$add_volume=$count*1000;
		}
		elseif((int)$product['units']==111) {
			$add_volume=$count;
		}
		else {
			return array(
				'success'=>false,
				'txt'=>'unit_incorrect_egais'
			);
		}

		$receipts_volume=$this->get_volume_from_receipts($mark[0]);
		$mark[0]['current_volume']-=$receipts_volume;
		if($mark[0]['current_volume']<$add_volume) {
			return array(
				'success'=>false,
				'current_volume'=>$mark[0]['current_volume'],
				'txt'=>'no_required_amount',
				'spill'=>$product['units']==796?false:true
			);
		}
		return array(
			'success'=>true,
			'current_volume'=>$mark[0]['current_volume']
		);
	}

	// Поиск информации по марке
	function search_mark($mark) {
		$mark=str_replace(' ', '', $mark);
		if(mb_strlen($mark)<11) {
			return array(
				'success'=>false,
				'txt'=>'incorrect_mark_code'
			);
		}
		$mark=$this->db->exec("SELECT m.current_volume, m.chpok, m.capacity, m.FormB, m.mark, p.* FROM egais_marks AS m JOIN products AS p ON p.id=m.product_id WHERE m.mark=? OR m.mark LIKE ? LIMIT 1", array($mark, '%'.$mark.'%'));
		if($mark) {
			return array(
				'success'=>true,
				'data'=>$mark[0]
			);
		}

		return array(
			'success'=>false,
			'txt'=>'not_found'
		);
	}

	// Изменяем объем алкоголя в бутылках
	function change_mark_volume($line, $type=1) {
		$mark=json_decode($line['mark'], true)[0];
		if(!$mark) {
			return array(
				'success'=>false,
				'txt'=>'not_found'
			);
		}

		$mark_data=$this->db->exec("SELECT * FROM egais_marks WHERE mark=? LIMIT 1", $mark);

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

		$volume=(float)$line['count'];
		if((int)$line['units_fr']==0) {
			// штуки
			$volume*=$mark_data[0]['capacity']*1000;
		}
		elseif((int)$line['units_fr']==41) {
			// литры
			$volume*=1000;
		}

		if($type==2) {
			// Возврат
			$volume=-$volume;
		}

		if($mark_data[0]['chpok']==0 && $mark_data[0]['current_volume']==$mark_data[0]['capacity']*1000 && $line['units_fr']!=0) {
			// Если бутылка не была вскрыта ранее, то вскрываем ее и создаем документ вскрытия
			$chpok=true;
		}
		else {
			$chpok=false;
		}

		$res=$this->db->exec("UPDATE egais_marks SET current_volume=?, chpok=? WHERE mark=?", array(min($mark_data[0]['current_volume']-$volume, $mark_data[0]['capacity']*1000), ($chpok?1:0), $mark));
		if($res===false) {
			return array(
				'success'=>false,
				'txt'=>'db_error'
			);
		}

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

	function get_volume_from_receipts($mark) {
		$receipt_sales=$this->f3->get('receipt_sales');
		$receipt_correct_sales=$this->f3->get('receipt_correct_sales');
		$receipt_return=$this->f3->get('receipt_return');
		$receipt_correct_return=$this->f3->get('receipt_correct_return');
		$mark_json='["'.$mark['mark'].'"]';
		$lines=$this->db->exec("SELECT l.count, r.type, l.units_fr FROM receiptlines AS l JOIN receipts AS r ON r.time=0 AND r.id=l.receipt_id WHERE l.mark=? AND l.complite_order=0", $mark_json);
		$receipts_volume=0;
		if($lines) {
			foreach($lines as $l) {
				if($l['units_fr']==0) {
					$line_volume=$l['count']*$mark[0]['capacity']*1000;
				}
				elseif($l['units_fr']==41) {
					$line_volume=$l['count']*1000;
				}
				else {
					$line_volume=$l['count'];
				}
				if($l['type']==$receipt_return || $l['type']==$receipt_correct_return) {
					$line_volume=-$line_volume;
				}
				$receipts_volume+=$line_volume;
			}
		}
		return $receipts_volume;
	}

	function close_bottles($product_id) {
		$bottles=array();
		$marks=$this->db->exec("SELECT * FROM egais_marks WHERE (current_volume>0 AND current_volume=(capacity*1000) OR chpok=0) AND product_id=?", $product_id);
		if($marks) {
			foreach($marks as $mark) {
				$mark['serial']=mb_substr($mark['mark'], 3, 3);
				$mark['number']=mb_substr($mark['mark'], 6, 8);

				$mark['current_volume']-=$this->get_volume_from_receipts($mark);
					
				if($mark['current_volume']<=0 || $mark['chpok']==1 || $mark['current_volume']!=$mark['capacity']*1000) continue;
				$bottles[]=$mark;
			}
		}
		return $bottles;
	}

	function open_bottles($products) {
		$bottles=array();
		foreach($products as $product) {
			$val=array(
				"%\"product_id\":\"".$product['product_id']."\"%"
			);
			$marks=$this->db->exec("SELECT m.*, p.title FROM products AS p JOIN egais_marks AS m ON m.product_id=p.id AND (m.current_volume>0 AND m.current_volume<(m.capacity*1000) OR m.chpok>0) WHERE p.cocktail LIKE ?", $val);
			if($marks) {
				foreach($marks as $mark) {
					$mark['serial']=mb_substr($mark['mark'], 3, 3);
					$mark['number']=mb_substr($mark['mark'], 6, 8);

					$mark['current_volume']-=$this->get_volume_from_receipts($mark);
						
					if($mark['current_volume']<=0) continue;

					if(isset($bottles[$mark['product_id']])) {
						$bottles[$mark['product_id']]['bottles'][]=$mark;
					}
					else {
						$bottles[$mark['product_id']]=array(
							'title'=>$mark['title'],
							'bottles'=>array(
								$mark
							)
						);
					}
				}
			}
		}
		return $bottles;
	}

	function check_double_certificate($data) {
		$this->reset();
		$this->load(array('product_id=? AND certificate=?', array($data['id'], $data['certificate'])), array('limit'=>1));
		if($this->dry()) return true;
		return false;
	}

	// Сумма чека без скидок
	function get_sum0($lines) {
		foreach($lines as $n=>$l) {
			if($l['loyalty']!=2) {
				$lines[$n]['price']=$l['price0'];
				$lines[$n]['discount']=0;
			}
		}
		return $this->get_sum($lines, 0, 0, 0, 0);
	}

	function cancel_receipt_sum_loyalty($receipt, $loyalty) {
		$l_id=array_column($loyalty, 'id');
		$this->load(array('receipt_id=? AND loyalty!=2 AND loyalty_id IN ('.implode(', ', $l_id).')', $receipt['id']));
		if($this->dry()) return;
		do {
			$this->price=$this->price0;
			$this->description='';
			$this->loyalty=0;
			$this->loyalty_id=0;
			$this->update();
		}
		while($this->skip());
	}
}
