<?php
namespace Controllers;

// Контроллер работы с API Агорты
class Api extends Controller {
	public $api_data, $auto_sinch=0, $neworders=0;

	public function __construct() {
		parent::__construct();
		$this->model=new \Models\Api($this->f3, $this->api_data['domen'], $this->api_data['pass'], $this->api_data['store_id'], $this->api_data['count']);
	}

	function set_api_count($api_count) {
		if(!is_numeric($api_count)) $api_count=5;
		if(!is_numeric($this->api_data['count'])) $this->api_data['count']=5;
		if($this->api_data['count']<$api_count) {
			$api_count=min($this->api_data['count']*2, $api_count);
		}
		$s=new \Models\Settings($this->f3, $this->db);
		$data=array(
			'store_id'=>$this->api_data['store_id'],
			'rm_id'=>$this->api_data['rm_id'],
			'rm_name'=>$this->api_data['rm_name'],
			'domen'=>$this->api_data['domen'],
			'pass'=>$this->api_data['pass'],
			'count'=>$api_count
		);
		$s->create_config_api($data);
	}

	// Установка СНО
	function sno() {
		$res['success']=true;
		$txt='';
		$time_start=microtime(true)+rand(1, 999999)/1000000;
		$this->db->exec('UPDATE synchronization SET time_start=?', $time_start);
		$sno=$this->model->sno();
		if($sno['success']===true) {
			$r=$this->db->exec("UPDATE fr_settings SET sno=?", $sno['sno']);
			if($r>=0) {
				$txt=$this->messages->message('save_successful')['txt'];
			}
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($sno['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$sno['debug'])$sno['debug']=array();
			$res['debug']=$sno['debug'];
			$res['success']=false;
			if($sno['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}

		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0');

		echo json_encode($res);
		exit();
	}

	// Функция синхронизации пользователей
	function users() {
		$res['success']=true;
		if($this->f3->get('GET.reload')) {
			$res['reload']='.users_list';
			$res['close_all_window']=true;
		}
		$txt='';
		$time_start=microtime(true)+rand(1, 999999)/1000000;
		$this->db->exec('UPDATE synchronization SET time_start=?', $time_start);
		$users=$this->model->users(); // получаем пользователей

		if(isset($users['api_count']) && $users['api_count']>0 && $users['api_count']!=$this->api_data['count']) {
			$this->set_api_count($users['api_count']);
		}

		if($users['success']===true) { // если все получили
			// Добавляем группы
			$sql="INSERT OR REPLACE INTO `usergroups` (`id`, `title`, `module`) VALUES ";
			$val=array();
			$in='';
			$val_in=array();
			// Формируем запросы на добавление, изменение или удаление групп
			foreach ($users['usergroups'] as $group) {
				if(!empty($val)) {
					$sql.=', ';
					$in.=', ';
				}
				$sql.="(?, ?, ?)";
				$in.='?';
				$val[]=$group['id'];
				$val[]=$group['title'];
				$val[]=$group['module'];
				$val_in[]=$group['id'];
			}
			// Выполняем запросы
			$groups_res=$this->db->exec($sql, $val);
			if($groups_res!==false) {
				$sql="DELETE FROM `usergroups` WHERE `id` NOT IN (".$in.")";
				$this->db->exec($sql, $val_in);
			}
			else {
				$mess=$this->messages->message('save_usergroups_error')['txt'];
				$res['success']=false;
				$txt.='<span class="false">'.$mess.'</span><br>';
			}


			// Добавляем пользователей
			$in='';
			$val_in=array();
			$u_sql=array();
			$u_val=array();
			foreach ($users['users'] as $user) {
				if(!empty($val_in)) {
					$in.=',';
				}
				$in.='?';
				$val_in[]=$user['id'];
				$sql="SELECT `id` FROM `users` WHERE `id`=? LIMIT 1";
				$u=$this->db->exec($sql, $user['id']);
				if(empty($u)) {
					$u_sql[]="INSERT INTO `users` (`id`, `name`, `short_name`, `group_id`, `pass`, `card`, `date_delete`, `hash`, `inn`, `type`, `kiosk`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
					$u_val[]=array(
						$user['id'],
						$user['name'],
						$user['short_name'],
						$user['group_id'],
						$user['pass'],
						$user['card'],
						$user['date_delete'],
						'',
						$user['inn'],
						$user['type'],
						$user['kiosk']
					);
				}
				else {
					$u_sql[]="UPDATE `users` SET `name`=?, `short_name`=?, `group_id`=?, `pass`=?, `card`=?, `date_delete`=?, `inn`=?, `type`=?, `kiosk`=? WHERE id=?";
					$u_val[]=array(
						$user['name'],
						$user['short_name'],
						$user['group_id'],
						$user['pass'],
						$user['card'],
						$user['date_delete'],
						$user['inn'],
						$user['type'],
						$user['kiosk'],
						$user['id']
					);
				}
			}

			// Выполняем запросы
			$users_res=$this->db->exec($u_sql, $u_val);
			if($users_res!==false) {
				$sql="DELETE FROM `users` WHERE `date_delete`<? AND `date_delete`>0";
				$this->db->exec($sql, strtotime('-15 days'));

				$sql="UPDATE `users` SET `date_delete`='".microtime(true)."' WHERE `date_delete`=0 AND `id` NOT IN (".$in.")";
				$this->db->exec($sql, $val_in);
			}
			else {
				$mess=$this->messages->message('save_users_error')['txt'];
				$res['success']=false;
				$txt.='<span class="false">'.$mess.'</span><br>';
			}

			if($txt=='') { // если текст сообщения еще не сформирован, то добавляем из последнего запроса
				$txt=$this->messages->message('success_users_synchronization')['txt'];
			}
			else {
				$this->logs->save_log($txt, 'error');
			}
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($users['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$users['debug'])$users['debug']=array();
			$res['debug']=$users['debug'];
			$res['success']=false;
			if($users['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		$this->db->exec('UPDATE synchronization SET time_start=0, users_update=?', time());
		$res['txt']=$txt;
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		$res['neworders']=$this->neworders;
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Загрузка категорий и товаров
	function products_load($time_update=0) {
		if(!is_numeric($time_update)) $tickets_update=0;
		$res['success']=true;
		$txt='';

		$data=$this->model->products($time_update); // загружаем продукты
		$mark_all=array();

		if(isset($data['api_count']) && $data['api_count']>0 && $data['api_count']!=$this->api_data['count']) {
			$this->set_api_count($data['api_count']);
		}

		if($data['success']===true) {
			// Добавляем категории товаров
			$sql=array();
			$val=array();
			foreach ($data['categories'] as $cat) {
				$sql[]="INSERT OR REPLACE INTO productcategories (id, parent_id, title, color, date_delete, date_update, icon, show, img, kiosk_noshow) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
				if(!$cat['icon']) {
					$cat['icon']='';
				}
				if(!$cat['kiosk_noshow']) {
					$cat['kiosk_noshow']=0;
				}
				if($cat['date_delete']>0) {
					$cat['kassa_show']=0;
				}
				$val[]=array(
					$cat['id'],
					$cat['parent_id'],
					$cat['title'],
					$cat['color'],
					$cat['date_delete'],
					$cat['date_update'],
					$cat['icon'],
					$cat['kassa_show'],
					$cat['img'],
					$cat['kiosk_noshow']
				);
				$time_update=$cat['date_update'];
				if($sql_delete!='') $sql_delete.=', ';
				$sql_delete.='?';
				$val_delete[]=$cat['id'];
			}
			if(!empty($sql)) {
				if(!$this->db->exec($sql, $val)) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
				sleep(1);
			}
			$this->db->exec("DELETE FROM productcategories WHERE date_delete<? AND date_delete>0", time()-3600*24*14);

			// Добавляем товары и штрих-коды
			$sql=array();
			$val=array();
			$bsql=array();
			$formb_sql=array();
			$bval=array();
			$dsql=array();
			$dval=array();
			$formb_val=array();
			$other_data_key=array('compound', 'kkal', 'proteins', 'fats', 'carbohydrates', 'complect');
			foreach ($data['products'] as $prod) {
				if(!isset($prod['related'])) {
					$prod['related']='';
				}
				else {
					$prod['related']=json_encode($prod['related']);
				}
				$sql[]="INSERT OR REPLACE INTO products (id, code, ppr, fast, title, short_title, img, product_description, category_id, stock, price, buy_price, vat, vat_type, date_delete, date_update, marking, marking_group, egais, alcocode, quantity, print_group, print_group_id, related, max_discount, add_bonus, stop, combo_data, partner_id, partner_type, units, sno, parent_id, multiple_sale, cocktail, opt_price_1, opt_price_2, opt_price_3, other_data, country_id, country_alpha2, gtd, plu) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
				$other_data=array();
				foreach($other_data_key as $key) {
					$other_data[$key]=$prod[$key];
				}
				$combo_data=json_decode($prod['combo_data'], true);
				if(!is_array($combo_data)) {
					$prod['combo_data']='';
				}
				$val[]=array(
					$prod['id'],
					mb_strtoupper($prod['code']),
					$prod['ppr'],
					$prod['fast'],
					$prod['title'],
					$prod['short_title'],
					$prod['img'],
					$prod['description'],
					$prod['category_id'],
					$prod['stock'],
					$prod['price'],
					$prod['buy_price'],
					$prod['vat'],
					$prod['vat_type'],
					$prod['date_delete'],
					$prod['date_update'],
					$prod['marking'],
					$prod['marking_group'],
					$prod['egais'],
					$prod['alcocode'],
					$prod['quantity'],
					$prod['print_group'],
					$prod['print_group_id'],
					$prod['related'],
					$prod['max_discount'],
					$prod['add_bonus'],
					$prod['stop']?$prod['stop']:0,
					$prod['combo_data'],
					$prod['partner_id'],
					$prod['partner_type'],
					$prod['okei']?$prod['okei']:0,
					$prod['sno'],
					$prod['parent_id']?$prod['parent_id']:0,
					$prod['multiple_sale'],
					$prod['cocktail']?json_encode($prod['cocktail']):'',
					$prod['opt_price_1']?$prod['opt_price_1']:0,
					$prod['opt_price_2']?$prod['opt_price_2']:0,
					$prod['opt_price_3']?$prod['opt_price_3']:0,
					json_encode($other_data),
					$prod['country_id'],
					$prod['country_alpha2'],
					$prod['gtd'],
					$prod['plu']??''
				);
				$dsql[]="DELETE FROM `barcodes` WHERE product_id=?";
				$dval[]=array($prod['id']);
				$formb_sql[]="DELETE FROM `egais_formb` WHERE product_id=?";
				$formb_val[]=array($prod['id']);
				if(isset($prod['formsb']) && !empty($prod['formsb'])) {
					foreach($prod['formsb'] as $formb) {
						$formb_sql[]="INSERT OR REPLACE INTO egais_formb (product_id, FormB, count, beer_capacity) VALUES (?, ?, ?, ?)";
						$formb_val[]=array(
							$prod['id'],
							$formb['FormB'],
							$formb['beer_count'],
							$formb['beer_capacity']
						);
					}
				}
				$time_update=$prod['date_update'];
				$barcodes=explode(',', $prod['barcodes']);
				if(!empty($barcodes)) {
					foreach ($barcodes as $barcode) {
						$bsql[]="INSERT OR REPLACE INTO barcodes (product_id, barcode) VALUES (?, ?)";
						$bval[]=array(
							$prod['id'],
							$barcode
						);
					}
				}
				//$dsql[]="DELETE FROM `egais_marks` WHERE product_id=?";
				//$dval[]=array($prod['id']);
				$marks_val=array($prod['id']);
				$not_in='';
				if(isset($prod['marks'])) {
					$marks=$prod['marks'];
					if(is_array($marks) && !empty($marks)) {
						foreach($marks as $mark) {
							if($not_in!='') $not_in.=', ';
							$not_in.='?';
							$marks_val[]=$mark['mark'];
							$mark_data=$this->db->exec("SELECT * FROM egais_marks WHERE mark=? LIMIT 1", $mark['mark']);
							$mark['product_id']=$prod['id'];
							$mark_all[$mark['mark']][]=$mark;
							if($mark_data) {
								$msql="UPDATE egais_marks SET current_volume=?, chpok=?, product_id=?, FormB=? WHERE mark=?";
								$mval=array(
									$mark['current_volume'],
									$mark['chpok'],
									$prod['id'],
									$mark['FormB'],
									$mark['mark']
								);
							}
							else {
								$msql="INSERT INTO egais_marks (mark, FormB, product_id, current_volume, capacity, chpok) VALUES (?, ?, ?, ?, ?, ?)";
								$mval=array(
									$mark['mark'],
									$mark['FormB'],
									$prod['id'],
									$mark['current_volume'],
									$mark['Capacity'],
									$mark['chpok']??0
								);
							}
							$this->db->exec($msql, $mval);
						}
					}
				}
				if($not_in!='') $not_in=' AND mark NOT IN ('.$not_in.')';
				$dsql[]="DELETE FROM `egais_marks` WHERE product_id=? ".$not_in;
				$dval[]=$marks_val;
			}
			if(!empty($sql)) {
				if(!$this->db->exec($sql, $val)) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
				sleep(1);
			}
			if(!empty($dsql)) {
				$d=$this->db->exec($dsql, $dval);
				if($d===false) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
			}
			if(!empty($bsql)) {
				if(!$this->db->exec($bsql, $bval)) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
			}

			if(!empty($formb_sql)) {
				if($this->db->exec($formb_sql, $formb_val)===false) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
			}

			if($txt!='') {
				$this->logs->save_log($txt, 'error');
			}

			$dtime=-(time()-1800);
			$this->db->exec("DELETE FROM `barcodes` WHERE product_id>? AND product_id<0", $dtime);
			$this->db->exec("DELETE FROM `products` WHERE id>? AND id<0", $dtime);
			// Если массивы с продуктами и категориями были не пустые, то надо продолжить
			if(count($data['categories'])>0 || count($data['products'])>0) {
				$time=time();
				$this->db->exec('UPDATE synchronization SET time_start=?, time_update=?', array($time, $time_update));
				$txt.='<br>'.$this->messages->message('update')['txt'];
				$res['next_step']=$time;
			}
			else {
				$txt='<br>'.$this->messages->message('save_successful')['txt'];
				$this->db->exec('UPDATE synchronization SET time_start=?, time_update=?', array(0, $time_update));
			}

		}
		else { // Если произошла ошибка
			foreach ($data['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			$res['txt']=$txt;
			if(!$data['debug'])$data['debug']=array();
			$res['debug']=$data['debug'];
			$res['success']=false;
			if($data['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
			$this->db->exec('UPDATE synchronization SET time_start=?, time_update=?', array(0, $time_update));
		}
		$res['txt']=$txt;
		$delete=$this->db->exec("SELECT id FROM products WHERE date_delete<? AND date_delete>0", time()-3600*24*14);
		if($delete) {
			$d_id=array_column($delete, 'id');
			$this->db->exec("DELETE FROM products WHERE date_delete<? AND date_delete>0", time()-3600*24*14);
			$this->db->exec("DELETE FROM barcodes WHERE product_id IN (".implode(', ', $d_id).")");
		}

		return $res;
	}

	// Загрузка обновленныйх категорий и товаров
	function products() {
		// Проверяем не запущена ли уже синхронизация.
		$sinch=$this->db->exec("SELECT * FROM synchronization WHERE time_start=0 OR time_start<".(time()-600)." LIMIT 1");
		if(!$sinch) {
			$res=array(
				'success'=>false,
				'txt'=>$this->messages->message('sync_is_already_running')['txt']
			);
		}
		else {
			$time_start=microtime(true)+rand(1, 999999)/1000000;
			$this->db->exec('UPDATE synchronization SET time_start=?', $time_start);
			$time_update=$sinch[0]['time_update'];
			$res=$this->products_load($time_update);
			if($this->f3->get('auto_sinch') && $res['success']) {
				$res['txt']=$this->messages->message('success_products_synchronization')['txt'];
			}
			$this->db->exec('UPDATE synchronization SET time_start=0');
		}
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Полная загрузка категорий и товаров
	function products_all() {
		// Проверка доступности сети
		$res=$this->model->is_online();
		if($res['success']!==true) {
			$res['success']=false;
			$res['txt']=$this->messages->message('no_internet')['txt'];
			echo json_encode($res);
			exit();
		}
		$time_start=$this->f3->get('GET.time_start'); // Узнаем время запуска синхронизации
		if(!$time_start) $time_start=0; // если время не задано, то это начало синхронизации
		// Проверяем не запущена ли уже синхронизация.
		$sinch=$this->db->exec("SELECT * FROM synchronization LIMIT 1");
		if($sinch[0]['time_start']==$time_start || ($time_start==0 && $sinch[0]['time_start']<time()-600) || $this->f3->get('GET.forcibly')) {
			if($time_start>0) { // Если синхронизация не только что началась, то время обновления берем из таблицы
				$time_update=$sinch[0]['time_update'];
			}
			else { // если синхронизация только что началась, то время обновления 0, чтобы получить все товары
				$time_update=0;
			}
			if($time_start==0) { // Если синхронизация только началась, то очищаем таблицы
				$this->db->exec('DELETE FROM productcategories');
				$this->db->exec('DELETE FROM products');
				$this->db->exec('DELETE FROM barcodes');
				$this->db->exec('DELETE FROM egais_marks');
				$this->db->exec('UPDATE device_synchronization SET time=0 WHERE type="clientsscales"');
				$this->db->exec('VACUUM');
			}
			$this->db->exec('UPDATE synchronization SET time_start=?', array(time()));
			$res=$this->products_load($time_update);
		}
		else {
			$mess=$this->messages->message('sync_is_already_running');
			$res['txt']=$mess['txt'];
			$res['success']=false;
		}

		if($res['next_step']) {
			$res['next_step']='/api/products_all?time_start='.$res['next_step'];
		}
		echo json_encode($res);
		exit();
	}

	// Изменить статус заказа
	function change_order_status() {
		$get=$this->f3->get('GET');
		$res=$this->model->change_order_status($get['id'], $get['status_id']);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if($res['success']===true) {
			$txt=$this->messages->message('save_successful')['txt'];
			$res['function']='save_order_status('.$get['status_id'].')';
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($res['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$res['debug'])$res['debug']=array();
		}

		$res['txt']=$txt;
		echo json_encode($res);
		exit();
	}

	// Загрузка списка статусов заказов
	function ordersstatuses() {
		$res['success']=true;
		$txt='';

		$data=$this->model->ordersstatuses();
		if(isset($data['api_count']) && $data['api_count']>0 && $data['api_count']!=$this->api_data['count']) {
			$this->set_api_count($data['api_count']);
		}
		if($data['success']===true) {
			$sql=array();
			$val=array();
			foreach ($data['status'] as $s) {
				$sql[]="INSERT OR REPLACE INTO ordersstatus (id, title) VALUES (?, ?)";
				$val[]=array(
					$s['id'],
					$s['title']
				);
			}
			if(!empty($sql)) {
				if(!$this->db->exec($sql, $val)) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
				sleep(1);
				$status_id=array_column($data['status'], 'id');
				$this->db->exec("DELETE FROM ordersstatus WHERE id NOT IN (".implode(", ",$status_id).")");
			}
			if($txt!='') {
				$this->logs->save_log($txt, 'error');
			}
			$txt='<br>'.$this->messages->message('save_successful')['txt'];
			$this->db->exec('UPDATE synchronization SET time_start=0, ordersstatuses=?', time());
		}
		else { // Если произошла ошибка
			foreach ($data['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$data['debug'])$data['debug']=array();
			$res['debug']=$data['debug'];
			$res['success']=false;
			if($data['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
			$this->db->exec('UPDATE synchronization SET time_start=0, ordersstatuses=?', time());
		}
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		$res['neworders']=$this->neworders;
		$res['txt']=$txt;
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Клиенты
	// Загрузка клиентов
	function partners_load($time_update=0) {
		if(!is_numeric($time_update)) $time_update=0;
		$res['success']=true;
		$txt='';

		$data=$this->model->partners($time_update); // загружаем клиентов
		if(isset($data['api_count']) && $data['api_count']>0 && $data['api_count']!=$this->api_data['count']) {
			$this->set_api_count($data['api_count']);
		}
		if($data['success']===true) {
			// Добавляем клиентов
			$sql=array();
			$val=array();
			foreach ($data['partners'] as $p) {
				$sql[]="INSERT OR REPLACE INTO partners (card, partner_id, group_id, name, email, phone, discount, date_delete, loyalty_type, bonus, bonus_type, bonus_pay, bonus_summ, bonus_bonus, bonus_add_sets, ignore_max_discount, inn, ie, lowername) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
				$val[]=array(
					$p['card'],
					$p['partner_id'],
					$p['group_id'],
					$p['name'],
					$p['email'],
					$p['phone'],
					$p['loyalty_type']==2 && $p['bonus_type']==1?$p['bonus_discount']:$p['discount'],
					$p['date_delete'],
					$p['loyalty_type'],
					$p['bonus'],
					$p['bonus_type'],
					$p['bonus_pay'],
					$p['bonus_summ'],
					$p['bonus_bonus'],
					$p['bonus_add_sets'],
					$p['ignore_max_discount'],
					$p['inn'],
					$p['ie'],
					mb_strtolower($p['name'])
				);
				$time_update=$p['date_update'];
			}
			if($this->sets['default_partnergroup']!=$data['default_group_id']); {
				$sql[]="INSERT OR REPLACE INTO settings (name, value) VALUES ('default_partnergroup', ?)";
				$val[]=array($data['default_group_id']);
				$this->sets['default_partnergroup']=$data['default_group_id'];
			}
			if(!empty($sql)) {
				if(!$this->db->exec($sql, $val)) {
					$txt.='<br>'.$this->messages->message('db_error')['txt'];
				}
				sleep(1);
			}
			if($txt!='') {
				$this->logs->save_log($txt, 'error');
			}

			// Если массив с клиентами был не пустый, то надо продолжить
			if(count($data['partners'])>0) {
				$time_start=time();
				$this->db->exec('UPDATE synchronization SET time_start=?, partners_update=?', array($time_start, $time_update));
				$txt.='<br>'.$this->messages->message('update')['txt'];
				$res['next_step']=$time_start;
			}
			else {
				$txt='<br>'.$this->messages->message('save_successful')['txt'];
				$this->db->exec('UPDATE synchronization SET time_start=?, partners_update=?', array(0, $time_update));
			}
		}
		else { // Если произошла ошибка
			foreach ($data['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$data['debug'])$data['debug']=array();
			$res['debug']=$data['debug'];
			$res['success']=false;
			if($data['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
			$this->db->exec('UPDATE synchronization SET time_start=?, partners_update=?', array(0, $time_update));
		}
		$res['txt']=$txt;
		return $res;
	}

	// Загрузка обновленных клиентов
	function partners() {
		// Проверяем не запущена ли уже синхронизация.
		$sinch=$this->db->exec("SELECT * FROM synchronization WHERE time_start=0 OR partners_update<".(time()-600)." LIMIT 1");
		if(!$sinch) {
			$res=array(
				'success'=>false,
				'txt'=>$this->messages->message('sync_is_already_running')['txt']
			);
		}
		else {
			$time_start=microtime(true)+rand(1, 999999)/1000000;
			$this->db->exec('UPDATE synchronization SET time_start=?, partners_timer=?', array($time_start, time()));
			$time_update=$sinch[0]['partners_update'];
			if(!$time_update)$time_update=0;
			$res=$this->partners_load($time_update);
			if($this->f3->get('auto_sinch') && $res['success']) {
				$res['txt']=$this->messages->message('success_partners_synchronization')['txt'];
			}
			$this->db->exec('UPDATE synchronization SET time_start=0');
		}
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		$res['neworders']=$this->neworders;
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Полная загрузка клиентов
	function partners_all() {
		$res=$this->model->is_online();
		if($res['success']!==true) {
			$res['success']=false;
			$res['txt']=$this->messages->message('no_internet')['txt'];
			echo json_encode($res);
			exit();
		}
		$time_start=$this->f3->get('GET.time_start'); // Узнаем время запуска синхронизации
		if(!$time_start) $time_start=0; // если время не задано, то это начало синхронизации
		// Проверяем не запущена ли уже синхронизация.
		$sinch=$this->db->exec("SELECT * FROM synchronization LIMIT 1");
		if($sinch[0]['time_start']==$time_start || ($time_start==0 && $sinch[0]['time_start']<time()-600) || $this->f3->get('GET.forcibly')) {
			if($time_start>0) { // Если синхронизация не только что началась, то время обновления берем из таблицы
				$time_update=$sinch[0]['partners_update'];
			}
			else { // если синхронизация только что началась, то время обновления 0, чтобы получить все товары
				$time_update=0;
			}
			if($time_start==0) { // Если синхронизация только началась, то очищаем таблицы
				$this->db->exec('DELETE FROM partners');
				$this->db->exec('VACUUM');
			}
			$this->db->exec('UPDATE synchronization SET time_start=?', array(time()));
			$res=$this->partners_load($time_update);
		}
		else {
			$mess=$this->messages->message('sync_is_already_running');
			$res['txt']=$mess['txt'];
			$res['success']=false;
		}

		if($res['next_step']) {
			$res['next_step']='/api/partners_all?time_start='.$res['next_step'];
		}
		echo json_encode($res);
		exit();
	}
	//

	// Отдаем чеки
	function tickets($json=true) {
		if(!is_bool($json))$json=true;
		$sinch=$this->db->exec("SELECT * FROM synchronization LIMIT 1");
		if($sinch[0]['time_start']<time()-600) {
			$time_start=round(microtime(true)+rand(1, 9999)/10000, 4);
			$this->db->exec("UPDATE synchronization SET time_start=?", $time_start);
			$time_update=$sinch[0]['tickets_update'];
			if(!$time_update)$time_update=0;
			$receipts=new \Models\Receipts($this->db, $this->f3);
			$certificates=new \Models\Certificates($this->db, $this->f3);
			$tickets=$receipts->select_receipts(array('((r.time>0 AND issued_order>0) OR (r.time>0 AND r.type>=?)) AND r.synch=0', array($this->f3->get('receipt_return'))), array('order'=>'issued_order', 'limit'=>$this->api_data['count']));
			$time_start_control=$this->db->exec("SELECT time_start FROM synchronization LIMIT 1");
			$time_start_control[0]['time_start']=(float)$time_start_control[0]['time_start'];
			if($tickets && ($time_start_control[0]['time_start']==$time_start || $this->f3->get('GET.forcibly'))) {
				foreach($tickets as $n=>$t) {
					$tickets[$n]['fsrar_id']=$this->sets['fsrar_id'];
					$tickets[$n]['rm_name']=$this->api_data['rm_name'];
					$tickets[$n]['certificates']=$certificates->receipt_certificates($t['id']);
				}

				$res=$this->model->tickets($tickets);
				$this->api_data['count']=(int)$this->api_data['count'];
				if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
					$this->set_api_count($res['api_count']);
				}
				if(!empty($tickets)) {
					$issued_orders=array_column($tickets, 'issued_order');
					$issued_orders=array_reverse($issued_orders);
					$tickets_update=array_shift($issued_orders);
					if(!$tickets_update) {
						$tickets_update=$time_update;
					}
				}
				else {
					$tickets_update=$time_update;
				}
				if($res['success']===true) {
					$res['txt']=$this->messages->message('save_successful')['txt'];
					$this->db->exec("UPDATE receipts SET synch=1 WHERE id IN (".implode(", ", array_column($tickets, 'id')).")");
					$this->db->exec("UPDATE synchronization SET time_start=0, tickets_update=?", $tickets_update);
				}
				else {
					$this->set_api_count(ceil($this->api_data['count']/2));
					foreach ($res['error'] as $er) {
						$txt.=$this->messages->message($er)['txt'].'<br>';
					}

					$res['txt']=$txt;
					if($res['success']===false) {
						if(!$res['debug'])$res['debug']=array();
						$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
					}
					$res['success']=false;
					$this->db->exec("UPDATE synchronization SET time_start=0");
				}
			}
			elseif($time_start_control[0]['time_start']==$time_start) {
				$res=array(
					'success'=>true,
					'txt'=>$this->messages->message('save_successful')['txt']
				);
				//$this->db->exec("UPDATE synchronization SET time_start=0, tickets_update=?", $time_update);
				$this->db->exec("UPDATE synchronization SET time_start=0");
			}
			else {
				$this->set_api_count(ceil($this->api_data['count']/2));
				$res=array(
					'success'=>false,
					'txt'=>$this->messages->message('sync_is_already_running')['txt']
				);
			}
			if($this->f3->get('auto_sinch') && $res['success']) {
				$res['txt']=$this->messages->message('success_tickets_synchronization')['txt'];
			}
		}
		else {
			$mess=$this->messages->message('sync_is_already_running');
			$res['txt']=$mess['txt'];
			$res['success']=false;
		}

		if($json) {
			$res['remote_receipts']=$this->f3->get('remote_receipts');
			if($this->auto_sinch==1) {
				return $res;
			}
			else {
				echo json_encode($res);
				exit();
			}
		}
	}

	// Загрузка префиксов для весового штрих-кода и штрих-кода карты клиента
	function barcodes_pr() {
		$res['success']=true;
		$txt='';
		$this->db->exec('UPDATE synchronization SET time_start=?', time());
		$pr=$this->model->barcodes_pr();
		if(isset($pr['api_count']) && $pr['api_count']>0 && $pr['api_count']!=$this->api_data['count']) {
			$this->set_api_count($pr['api_count']);
		}
		if($pr['success']===true) {
			$sql=array();
			$val=array();
			foreach ($pr['barcodes_pr'] as $name => $value) {
				$sql[]="INSERT OR REPLACE INTO settings (name, value) VALUES (?, ?)";
				$val[]=array($name, $value);
			}
			$r=$this->db->exec($sql, $val);
			if($r!==false) {
				$txt=$this->messages->message('save_successful')['txt'];
			}
			else {
				$txt=$this->messages->message('db_error')['txt'];
			}
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($pr['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$pr['debug'])$pr['debug']=array();
			$res['debug']=$pr['debug'];
			$res['success']=false;
			if($pr['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0');

		echo json_encode($res);
		exit();
	}

	// Программы лояльности
	function loyalty() {
		$res['success']=true;
		$txt='';
		$this->db->exec('UPDATE synchronization SET time_start=?', time());
		$loyalty=$this->model->loyalty();
		if(isset($loyalty['api_count']) && $loyalty['api_count']>0 && $loyalty['api_count']!=$this->api_data['count']) {
			$this->set_api_count($loyalty['api_count']);
		}
		if($loyalty['success']===true) {
			$loyalty_id='';
			if($loyalty['loyalty']) {
				$loyalty_id=implode(',', array_column($loyalty['loyalty'], 'id'));
			}
			$sql=array();
			$val=array();
			foreach ($loyalty['loyalty'] as $l) {
				$sql[]="INSERT OR REPLACE INTO loyalty (id, date_start, date_end, title, d1, d2, d3, d4, d5, d6, d7, client, partnergroup, data, ignor_maxdiscount, action_type, certificates) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
				$val[]=array(
					$l['id'],
					$l['date_start'],
					$l['date_end'],
					$l['title'],
					$l['d1'],
					$l['d2'],
					$l['d3'],
					$l['d4'],
					$l['d5'],
					$l['d6'],
					$l['d7'],
					$l['client'],
					$l['partnergroup'],
					$l['data'],
					$l['ignor_maxdiscount'],
					$l['action_type'],
					$l['certificates']
				);
			}
			if($sql) {
				$r=$this->db->exec($sql, $val);
			}
			if($r!==false || empty($sql)) {
				$txt=$this->messages->message('success_loyalty_synchronization')['txt'];
				//Скидки
				if($loyalty['discounts']) {
					$sql="INSERT OR REPLACE INTO discounts (value) VALUES ";
					$val=array();
					foreach ($loyalty['discounts']['discounts'] as $value) {
						if(!empty($val)) $sql.=', ';
						$sql.='(?)';
						$val[]=$value;
					}
				}
				if(!empty($val)) {
					$r=$this->db->exec($sql, $val);
					if($r===false) {
						$txt=$this->messages->message('db_error')['txt'];
					}
				}
			}
			else {
				$txt=$this->messages->message('db_error')['txt'];
			}
			// Удаляем старые акции
			$sql="DELETE FROM `loyalty` WHERE `date_end`<=?";
			if($loyalty_id!='') {
				$sql.=" OR id NOT IN (".$loyalty_id.")";
			}
			else {
				$sql.=" OR id>0";
			}
			$this->db->exec($sql, time());
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($loyalty['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$loyalty['debug'])$loyalty['debug']=array();
			$res['debug']=$loyalty['debug'];
			$res['success']=false;
			if($loyalty['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0, loyalty=?', time());
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Добавляем документы для фискализации в БД
	function add_remote_receipts($receipts) {
		if(is_array($receipts)) {
			// Проверяем существование чеков
			$exists=array();
			$in='-1';
			$val=array();
			foreach ($receipts as $r) {
				$in.=', ?';
				$val[]=$r['id'];
			}
			$sql="SELECT id FROM `receipts` WHERE `remote` IN (".$in.")";
			$res=$this->db->exec($sql, $val);
			if($res) {
				foreach ($res as $r) {
					$exists[$r['remote']]=$r['id'];
				}
			}

			$add=0;
			foreach ($receipts as $r) {
				if(!isset($exists[$r['remote']])) {
					// Добавляем новый чек
					$sql="INSERT INTO `receipts` (`user_id`, `rm`, `store`, `time`, `sum`, `discount`, `client`, `partner_id`, `remote`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
					$client=$r['other']['phone'];
					if($r['other']['email']) {
						$client=$r['other']['email'];
					}

					$val=array(
						$r['user_id'],
						$this->api_data['rm_id'],
						$this->api_data['store_id'],
						-1,
						$r['sum'],
						0,
						$client,
						$r['partner_id'],
						$r['id']
					);
					$res=$this->db->exec($sql, $val); 
					if($res===false) {
						return array(
							'success'=>false,
							'txt'=>'db_error'
						);
					}
					$receipt_id=$this->db->lastInsertId();

					// Добавляем товары
					if($r['receiptlines']) {
						$sql="INSERT INTO `receiptlines` (`receipt_id`, `product_id`, `product_title`, `price`, `price0`, `vat`, `vat_type`, `count`, `line_discount`, `discount`) VALUES ";
						$val=array();
						foreach ($r['receiptlines'] as $l) {
							if(!empty($val)) $sql.=', ';
							$sql.="(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
							$val[]=$receipt_id;
							$val[]=$l['product_id'];
							$val[]=$l['title'];
							$val[]=$l['price']-($l['price']/100*$l['discount']);
							$val[]=$l['price'];
							$val[]=$l['vat'];
							$val[]=$l['vat_type'];
							$val[]=$l['count'];
							$val[]=$l['discount'];
							$val[]=0;
						}
						$res=$this->db->exec($sql, $val);
						if($res===false) {
							$this->db->exec("DELETE FROM `receipts` WHERE `id`=? LIMIT 1", $receipt_id);
							return array(
								'success'=>false,
								'txt'=>'db_error'
							);
						}
					}
					$add++;
				}
			}
		}

		return array(
			'success'=>true,
			'count'=>$add,
			'txt'=>'successfully_added_fiscalization'
		);
	}

	// Запрашиваем время выгрузки БД
	function db_upload_time() {
		$this->db->exec('UPDATE synchronization SET time_start=?', time());
		$res=$this->model->db_upload_time($this->api_data['rm_id']);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if($res['success']===true && $res['time']<time()-$this->f3->get('db_upload_time')*3600*24) {
			// Выгрузить БД
			$res=$this->dbupload();
		}
		elseif(!$res['success']) { // если ответ от сервера не успешный
			$txt='';
			foreach ($res['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$res['debug'])$res['debug']=array();
			$res['success']=false;
			if($res['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0');
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Запрашиваем баланс аккаунта
	function balance() {
		$this->db->exec('UPDATE synchronization SET time_start=?', time());
		$res=$this->model->balance();
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if($res['success']===true) {
			$settings=new \Models\Settings($this->f3, $this->db);
			$settings_res=$settings->save_base(array('balance'=>$res['balance'], 'balance_alarm'=>$res['alarm']?1:0));
			if($settings_res['success']) {
				if($res['balance']>0) {
					$txt=$this->messages->message('full_version')['txt'];
				}
				else {
					$txt=$this->messages->message('limited_version')['txt'];
				}
			}
			else {
				$txt=$this->messages->message($settings_res['txt'])['txt'];
			}
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($res['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$res['debug'])$res['debug']=array();
			$res['success']=false;
			if($res['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}

		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0');
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Запрашиваем документы на удаленную фискализацию
	function get_remote_receipts() {
		$res['success']=true;
		$txt='';
		$sinch=$this->db->exec("SELECT * FROM synchronization LIMIT 1");
		$this->db->exec('UPDATE synchronization SET time_start=?', time());

		// Список документов, которые были фискализированны с прошлого раза
		//$r=new \Models\Receipts($this->db, $this->f3);
		//$tickets=$r->success_fiscalization($sinch[0]['fiscalization']);

		$add=0;
		$receipts=$this->model->get_remote_receipts($this->api_data['rm_id']);
		if(isset($receipts['api_count']) && $receipts['api_count']>0 && $receipts['api_count']!=$this->api_data['count']) {
			$this->set_api_count($receipts['api_count']);
		}
		if($receipts['success']===true) {
			// Добавляем в базу полученные чеки
			$res=$this->add_remote_receipts($receipts['receipts']);
			$add=$res['count'];
			$txt=$this->messages->message($res['txt'])['txt'];
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($receipts['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$receipts['debug'])$receipts['debug']=array();
			$res['debug']=$receipts['debug'];
			$res['success']=false;
			if($receipts['success']===false) {
				$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
			}
		}
		$res['remote_receipts']=$this->f3->get('remote_receipts')+$add;
		$res['txt']=$txt;
		$this->db->exec('UPDATE synchronization SET time_start=0, fiscalization=?', microtime(true));

		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	function dbupload() {
		$res=$this->model->dbupload($this->api_data['rm_id']);
		if($res['success']===true) {
			$txt=$res['txt'];
		}
		else { // если ответ от сервера не успешный
			$txt='';
			foreach ($res['error'] as $er) {
				$txt.=$this->messages->message($er)['txt'].'<br>';
			}
			if(!$res['debug'])$res['debug']=array();
			$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
		}
		$res['txt']=$txt;
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// синхронизация ошибок синхронизации
	function logs() {
		$sinch=$this->db->exec("SELECT logs FROM synchronization LIMIT 1");
		$this->db->exec('UPDATE synchronization SET time_start=?', time());
		$logs=$this->logs->select_log(array('time>?', $sinch[0]['logs']), array('order'=>'time', 'limit'=>$this->api_data['count']));
		if($logs) {
			$times=array_reverse(array_column($logs, 'time'));
			$res=$this->model->logs($this->api_data['rm_name'], $logs);
			if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
				$this->set_api_count($res['api_count']);
			}
			if($res['success']===true) {
				$res['txt']=$this->messages->message('successfully_synchronization_logs')['txt'];
			}
			else {
				$txt='';
				foreach ($res['error'] as $er) {
					$txt.=$this->messages->message($er)['txt'].'<br>';
				}
				if(!$res['debug'])$res['debug']=array();
				$res['success']=false;
				if($res['success']===false) {
					$this->logs->save_log($txt.implode(';<br>', $res['debug']), 'error');
				}
				$res['txt']=$txt;
			}
		}
		else {
			$times[0]=time();
			$res['success']=true;
			$res['txt']=$this->messages->message('successfully_synchronization_logs')['txt'];
		}
		if($res['success']==true) {
			$this->db->exec('UPDATE synchronization SET time_start=0, logs=?', $times[0]);
		}
		else {
			$this->db->exec('UPDATE synchronization SET time_start=0');
		}
		$this->logs->delete_log(array('time<?', time()-3600*24*7));
		$res['remote_receipts']=$this->f3->get('remote_receipts');
		$res['neworders']=$this->neworders;
		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	// Авто синхронизация
	function auto() {
		$this->auto_sinch=1;
		$this->f3->set('auto_sinch', 1);
		$sinch=$this->db->exec("SELECT * FROM synchronization WHERE time_start=0 OR time_start<".(time()-600)." LIMIT 1");

		// Для любого режима (автономного и нет) проверяем версию, раз в сутки
		// Ошибки нас не интересуют
		if(!empty($sinch) && $sinch[0]['get_update']<time()-3600*24) {
			$this->db->exec("UPDATE synchronization SET get_update=?", time());
			$res=$this->new_version();
			if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
				$this->set_api_count($res['api_count']);
			}
			$this->sets['update_stage']=(int)$res['update_stage'];
		}

		// Кол-во ошибок синхронизации
		if((int)$this->sets['autonomous']==1) {
			exit();
		}
		$this->neworders=0;
		$new_orders_res=$this->model->neworderscount();
		if($new_orders_res['success']) {
			$this->neworders=$new_orders_res['count'];
		}

		if(isset($sinch[0]['auto_sinch']) && $sinch[0]['auto_sinch']<0) {
			$sinch[0]['auto_sinch']=1;
			$this->db->exec("UPDATE synchronization SET auto_sinch=1");
		}

		if(!$sinch) {
			$res['success']=false;
			$res['txt']=$this->messages->message('sync_is_already_running')['txt'];
		}
		elseif($sinch[0]['auto_sinch']>time()-$this->f3->get('synchronization_timer')*60) {
			$res['success']=false;
			$res['txt']=$this->messages->message('no_synchronization_required')['txt'];
		}
		else {
			$result=array(
				'success'=>true,
				'txt'=>'',
				'update_stage'=>(int)$this->sets['update_stage'] // Этап обновления из настроек, чтобы показывать мерцающую кнопку
			);
			$res=$this->balance();
			$balance=$res['balance'];
			$balance_alarm=$res['alarm'];
			$agorta_time=$res['time'];

			if($balance<=0) {
				$this->db->exec("UPDATE synchronization SET auto_sinch=?", time());
				echo json_encode($res);
				exit();
			}

			$this->db_upload_time();

			$t=time();
			$res=$this->get_remote_receipts();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['get_remote_receipts'] = time()-$t;

			$t=time();
			$this->db->exec("UPDATE synchronization SET auto_sinch=?", time());
			$res=$this->users();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}			
			$result['time']['users'] = time()-$t;

			if($sinch[0]['clients_scales']<time()-$this->f3->get('synchronization_clients_scales_timer')*60) {
				$t=time();
				$this->db->exec("UPDATE synchronization SET clients_scales=?", time());
				$res=$this->clients_scales();
				if(!$res['success']) {
					$result['success']=false;
					$result['txt'].=$res['txt'].'<br>';
				}
				$result['time']['clients_scales'] = time()-$t;
			}

			$t=time();
			$this->db->exec("UPDATE synchronization SET auto_sinch=?", time());
			$res=$this->ordersstatuses();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['ordersstatuses'] = time()-$t;

			$t=time();
			$this->db->exec("UPDATE synchronization SET auto_sinch=?", time());
			$res=$this->logs();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['logs'] = time()-$t;

			$t=time();
			$this->db->exec("UPDATE synchronization SET loyalty=?", time());
			$res=$this->loyalty();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['loyalty'] = time()-$t;
			
			$t=time();
			$res=$this->tickets();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['tickets'] = time()-$t;

			$t=time();
			$res=$this->products();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['products'] = time()-$t;

			$t=time();
			$res=$this->partners();
			if(!$res['success']) {
				$result['success']=false;
				$result['txt'].=$res['txt'].'<br>';
			}
			$result['time']['partners'] = time()-$t;

			if($result['success']) {
				$result['txt']=$this->messages->message('successfully_synchronization')['txt'];;
			}
			$this->db->exec("UPDATE synchronization SET auto_sinch=?", time());
			$res=$result;
			$res['balance']=$balance;
			$res['balance_alarm']=$balance_alarm;
			$res['time_alarm']=round(abs($agorta_time-time())/60)>10?true:false;
		}
		$res['neworders']=$this->neworders;
		$res['update_stage']=$this->sets['update_stage'];
		// Кол-во чеков для удаленной фискализации
		$res['remote_receipts']=$this->db->exec("SELECT COUNT(*) AS count FROM `receipts` WHERE `remote`>0 AND `time`<0")[0]['count'];
		echo json_encode($res);
		exit();
	}

	function searchsubdomain() {
		echo $this->model->searchsubdomain($this->f3->get('GET.term'));
		exit();
	}

	function getstores() {
		$get=$this->f3->get('GET');
		$res=$this->model->getstores($get);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		$options='';
		if($res['success'] && $res['stores']) {
			foreach($res['stores'] as $s){
				$options.='<option value="'.$s['id'].'"';
				if($this->api_data['store_id']==$s['id']) {
					$options.=' selected="selected" ';
				}
				$options.='>'.$s['title'].'</option>';
			}
		}
		else {
			$res['error'][0]=$this->messages->message($res['error'][0])['txt'];
		}
		$res['options']=$options;
		echo json_encode($res);
		exit();
	}

	function deliveryaction() {
		$url=html_entity_decode(urldecode($this->f3->get('GET.url')));
		$res=$this->model->deliveryaction($url);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if(!$res['success']) {
			$res['error'][0]=$this->messages->message($res['error'][0])['txt'];
		}
		echo json_encode($res);
		exit();
	}

	function new_version () {
		$res=$this->model->new_version(0);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if(!$res['success']) {
			if(!is_array($res['error'])) {
				$res['error']=array($res['error']);
			}
			$res['error'][0]=$this->messages->message($res['error'][0])['txt'];
		}
		$res['update_stage']=$this->sets['update_stage'];
		if($res['success']===true) {
			if($res['version']['version']!=$this->f3->get('site_version')) {
				// Если нужно обновляться, и еще нет об этом пометки, то ставим этап обновления 1
				if($res['update_stage']==0) $res['update_stage']=1;
				// Иначе останется как было
			}
		}
		if($res['update_stage']!=$this->sets['update_stage']) {
			// Если этап изменился, то сохраняем его в настройках
			$this->db->exec("INSERT OR REPLACE INTO settings (name, value) VALUES ('update_stage', ?)", $res['update_stage']);
		}

		if($this->auto_sinch==1) {
			return $res;
		}
		else {
			echo json_encode($res);
			exit();
		}
	}

	function clients_scales() {
		$scales=new \Models\Clientsscales($this->db, $this->f3, $this->api_data);
		$res=$scales->products_update();
		$res['txt']=$this->messages->message($res['txt'])['txt'];
		return $res;
	}

	function dbbackups() {
		$get=$this->f3->get('GET');
		if(!isset($get['all']) || $get['all']==0) {
			$rm_id=$this->api_data['rm_id'];
		}
		else {
			$rm_id=null;
		}

		if(!isset($get['page']) || !is_numeric($get['page']) || $get['page']<1) $get['page']=1;

		$res=$this->model->dbbackups($rm_id, $get['page']);
		if(isset($res['api_count']) && $res['api_count']>0 && $res['api_count']!=$this->api_data['count']) {
			$this->set_api_count($res['api_count']);
		}
		if(!$res['success']) {
			if(!is_array($res['error'])) {
				$res['error']=array($res['error']);
			}
			$res['error']=$this->messages->message($res['error'][0])['txt'];
		}
		echo json_encode($res);
		exit();
	}
}
