OSDN Git Service

44a4527fdfb72c86c27fa9f77a1f30ea87334e62
[invent/invent.git] / controllers / ItemsController.php
1 <?php
2
3 namespace app\controllers;
4
5 use Yii;
6 use app\models\Items;
7 use app\models\Import;
8 use app\models\Check;
9 use app\models\Moving;
10 use app\models\Locations;
11 use app\models\ItemsSearch;
12 use app\models\MovingSearch;
13 use app\models\Status;
14 use app\models\User;
15 use yii\web\Controller;
16 use yii\web\NotFoundHttpException;
17 use yii\web\UploadedFile;
18 use yii\filters\VerbFilter;
19
20 use kartik\mpdf\Pdf;
21 use \phpexcel;
22
23 #require "/vendor/phpoffice/phpexcel/Classes/PHPExcel.php";
24
25 /**
26  * ItemsController implements the CRUD actions for Items model.
27  */
28 class ItemsController extends Controller
29 {
30     /**
31      * {@inheritdoc}
32      */
33     public function behaviors()
34     {
35         return [
36             'verbs' => [
37                 'class'   => VerbFilter::className(),
38                 'actions' => [
39                     'delete' => [ 'POST' ],
40                 ],
41             ],
42         ];
43     }
44
45     /**
46      * Добавление предмета/оборудование если его нет
47      * @param array $options
48      *        string 'invent'
49      *        string 'model'
50      *        string 'comment'
51      *        string|NULL 'type'
52      *        string|NULL 'netname'
53      *        string|NULL 'os'
54      *        string|NULL 'mac'
55      *        string|NULL 'serial'
56      *        string|NULL 'product'
57      *        string|NULL 'modelnumber'
58      * @return integer|FALSE
59      */
60     public static function addIfNeed($options)
61     {
62         $result = [
63             'id' => FALSE,
64             'error' => Yii::t('items', 'Items: Key field missing "invent", "serial", "model"') . print_r($options, TRUE),
65         ];
66         // Если указан инвентарный номер
67         if (is_array($options) && isset($options[ 'invent' ]))
68         {
69             $item = Items::find()
70                 ->where([ 'invent' => $options[ 'invent' ]]); // Ищем оборудование с инвентарным номером.
71             // Если указан серийный номер
72             if (isset($options[ 'serial' ])) {
73                 $item = $item->andWhere([ 'like', 'serial', $options[ 'serial' ]]); // Ищем дополнительно с серийным номером
74             }
75             $item = $item->all(); // Получаем все записи
76
77             if (count($item) > 0) // Записи найдены, выводим первую совпавшую
78             {
79                 $result[ 'id' ] = $item[ 0 ]->id;
80                 $result[ 'error' ] = '';
81             }
82             else
83             {
84                 // Внесённого оборудования не найдено. Добавим новую запись
85                 if (isset($options[ 'model' ]))
86                 {
87                     $model = ModelsController::addIfNeed($options);
88                     if ($model[ 'id' ] === FALSE)
89                     {
90                         $result[ 'error' ] .= $model[ 'error' ] . '<br />';
91                     }
92                     // Создаём новую запись предмета/оборудования
93                     $item = new Items();
94                     $item->name        = isset($options[ 'netName' ]) ? $options[ 'netName' ] : NULL; // Сетевое имя
95
96                     $item->model_id    = $model[ 'id' ];                                              // идентификатор модели (Подготовлено для преобразования)
97
98                     $item->invent      = isset($options[ 'invent' ]) ? $options[ 'invent' ] : NULL;   // Инвентарный номер
99                     $item->comment     = isset($options[ 'comment' ]) ? $options[ 'comment' ] : NULL; // Коментарий
100                     $item->os          = isset($options[ 'os' ]) ? $options[ 'os' ] : NULL;           // Операционная система
101                     $item->mac         = isset($options[ 'mac' ]) ? $options[ 'mac' ] : NULL;         // MAC-адрес
102                     $item->serial      = isset($options[ 'serial' ]) ? $options[ 'serial' ] : NULL;   // Серийный номер
103                     $item->checked     = false;                                                       // Не инвентризирован (требует внимания после импорта)
104                     // Сохраняем запись
105                     if ($item->validate() && $item->save())
106                     {
107                         $result[ 'id' ] = $item->id; // Возвращаем идентификатор записанного оборудования
108                         $result[ 'error' ] = '';
109                     }
110                     else
111                     {
112                         $result[ 'error' ] .= Yii::t('items', 'Items: Failed to add entry') . print_r($item->errors(), TRUE);
113                     }
114                 }
115             }
116         }
117         return $result;
118     }
119
120     /**
121      * Формирование PDF файла для печати QR-кодов для наклеек
122      * @param integer|array|null id
123      * @return mixed
124      */
125     public function actionPrint()
126     {
127         if (! User::canPermission('takingInventory') ) {
128             return $this->redirect(['site/index']);
129         }
130         // Список предметов/оборудования, если есть
131         $id = Yii::$app->request->get('id');
132
133         $models = Items::find();
134         if (isset($id))
135             if (is_array($id))
136             {
137                 $models = $models->where([ 'in', 'id', $id ]); // Несколько предметов/оборудования
138             } else
139             {
140                 $models = $models->where([ 'id' => $id ]); // Один предмет/оборудование
141             }
142         $models = $models->all(); // Формирование списка
143
144         $pdf = Yii::$app->pdf; // Pабота с PDF
145
146         $pdf->methods[ 'SetHeader' ] = ''; // Yii::t('items', 'Items');
147         $pdf->methods[ 'SetFooter' ] = ''; // ['{PAGENO}'];
148         // Границы листа
149         $pdf->marginLeft   = 5;
150         $pdf->marginRight  = 5;
151         $pdf->marginTop    = 9;
152         $pdf->marginBottom = 15;
153         // Имя файла для выгрузки, по умолчанию document.pdf
154         $pdf->filename     = Yii::t('app', Yii::$app->name) . ' (' . Yii::t('items', 'Items') . ').pdf';
155
156         // Заполнение страницы данными
157         $pdf->content = $this->renderPartial('print', [ 'models' => $models ]);
158
159         // Выгрузка PDF
160         return $pdf->render();
161     }
162
163     /**
164      * Процедура начала инвентаризации.
165      * @return mixed
166      */
167     public function actionStart_checking()
168     {
169         // Проверка доступа для проведения инвентаризации
170         if (! User::canPermission('takingInventory') ) {
171             // Переход к списку предметов/оборудования, если доступ не разрешён.
172             return $this->redirect(['index']);
173         }
174         // Запрос на получение списка идентификаторов предметов/оборудования, которые списаны
175         $modelS = Moving::find()
176             ->select('item_id')
177             ->joinWith('status')
178             ->Where([ 'ilike', Status::tableName() . '.name', 'Списано' ]);
179
180         // Получаем список всех предметов/оборудования, кроме списанного
181         $model = Items::find()
182             ->select('id')
183             ->innerJoin([ 'm' => $modelS ], 'not m.item_id = id')
184             ->all();
185
186         // Устанавливаем флаг непроинвентаризированных для всех предметов/оборудования из полученного списка.
187         Items::updateAll([ 'checked' => false ], [ 'in', 'id', $model ]);
188
189         // Переход к списку предметов/оборудования.
190         return $this->redirect([ 'index' ]);
191     }
192
193     /**
194      * Инвентаризация
195      * @param string|null $qrcheck считанный QR-код
196      * @return mixed
197      */
198      public function actionCheck()
199      {
200         // Проверка доступа для проведения инвентаризации
201         if (! User::canPermission('takingInventory') ) {
202             // Показ стартовой страницы, если доступ не разрешён.
203             return $this->redirect(['site/index']);
204         }
205
206         $model = new Check();
207         $message = '';
208         if ($model->load(Yii::$app->request->post()))
209         {
210             if ((! empty($model->qrcheck)) && strpos($model->qrcheck, ',') !== false)
211             {
212                 $keys = explode(',', $model->qrcheck);
213                 Items::updateAll([ 'checked' => true ], [ 'invent' => trim($keys[ 0 ]), 'serial' => trim($keys[ 1 ]) ]);
214                 $items = Items::find()->where([ 'invent' => trim($keys[ 0 ]), 'serial' => trim($keys[ 1 ]) ])->all();
215                 //$message = '[0] = "' . $keys[0] . '", [1] = "' . $keys[1] . '"<br />';
216                 foreach ($items as $row)
217                 {
218                     $message .= $row->modelName . ' (' . $row->id . ')';
219                 }
220                 if ($message != '')
221                     $message = Yii::t('items', 'Checked item(s): ') . $message;
222                 $model->qrcheck = '';
223             }
224         }
225         $searchModel = new ItemsSearch();
226         $dataProvider = $searchModel->noinvent($model);
227
228         return $this->render('check', [
229             'message'      => $message,
230             'model'        => $model,
231             'searchModel'  => $searchModel,
232             'dataProvider' => $dataProvider,
233         ]);
234      }
235
236     /**
237      * Список всех предметов/оборудования.
238      * @return mixed
239      */
240     public function actionIndex()
241     {
242         if (! User::canPermission('createRecord') )
243         {
244             return $this->redirect(['site/index']);
245         }
246         $searchModel = new ItemsSearch();
247         if (isset(Yii::$app->request->queryParams['id']))
248         {
249             $id = Yii::$app->request->queryParams['id'];
250             $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
251             //$dataProvider->query->select(Items::tableName() . '.id');
252             $pageSize = $dataProvider->pagination->pageSize;
253             $dataProvider->pagination = FALSE;
254             $rows = $dataProvider->getModels();
255             $page = 0;
256             foreach ($rows as $key => $val)
257             {
258                 if ($id == $val->id)
259                 {
260                     $page = ceil(($key + 1) / $pageSize);
261                     break;
262                 }
263             }
264             return $this->redirect(['index', 'page' => $page]);
265         }
266         $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
267
268         return $this->render('index', [
269             'searchModel' => $searchModel,
270             'dataProvider' => $dataProvider,
271         ]);
272     }
273
274     /**
275      * Импортирование строк товаров из массива
276      */
277     public function doImport($arrayRows)
278     {
279         // Инициализация счётчиков
280         $arrayReturn = [
281             'countRows'     => count($arrayRows),
282             'countImported' => 0,
283             'countExists'   => 0,
284             'countErrors'   => 0,
285             'errors'        => '',
286         ];
287         
288         // Проверка наличия ключевых полей
289         if ((!isset($arrayRows[ 0 ][ 'model' ]))
290             || (!isset($arrayRows[ 0 ][ 'invent' ]))
291             || (!isset($arrayRows[ 0 ][ 'location' ]))
292             || (!isset($arrayRows[ 0 ][ 'region' ]))
293             || (!isset($arrayRows[ 0 ][ 'date' ]))
294         )
295         {
296             // Сообщение об ошибке
297             $arrayReturn[ 'countErrors' ] = count($arrayRows);
298             $arrayReturn[ 'errors' ] .= '<br />' . Yii::t('import', 'Skip all. Key column not found: ') . print_r($arrayRows[0], TRUE);
299         }
300         else
301         {
302             // Просмотрим весь массив
303             foreach($arrayRows as $row)
304             {
305                 // ПОлучим местоположения
306                 $location = LocationsController::addIfNeed($row); // Получение идентификатора расположения
307                 if ( $location[ 'id' ] === FALSE)
308                 {
309                     // Сообщим об ошибке
310                     $arrayReturn[ 'countErrors' ]++;
311                     $arrayReturn[ 'errors' ] .= '<br />' . Yii::t('import', 'Location: {location} ({region})', $row) . ' :: ' . $location[ 'error' ];
312                 }
313                 else
314                 {
315                     // Попробуем найти или добавить предмет/оборудование
316                     $item = $this->addIfNeed($row);
317                     if ($item[ 'id' ] === FALSE)
318                     {
319                         $arrayReturn[ 'countErrors' ]++;
320                         $arrayReturn[ 'errors' ] .= '<br />' . $item[ 'error' ];
321                     }
322                     else
323                     {
324                         // Проверка, что предмет/оборудование уже были в базе
325                         $item = Items::find()->where([ 'id' => $item[ 'id' ]])->one();
326                         if ($item->checked === TRUE)
327                         {
328                             $arrayReturn[ 'countExists' ]++;
329                         }
330                         else
331                         {
332                             $state = isset($row[ 'status' ]) ? StatusController::addIfNeed($row) : StatusController::addIfNeed([ 'name' => 'Склад' ]);
333                             if ( $state[ 'id' ] === FALSE )
334                             {
335                                 // Сообщим об ошибке
336                                 $arrayReturn[ 'countErrors' ]++;
337                                 $arrayReturn[ 'errors' ] .= '<br />' . $state[ 'error' ];
338                             }
339                             else
340                             {
341                                 // Новый предмет/оборудование. Пробуем добавить первое перемещение
342                                 $moving = new Moving();
343                                 $moving->date        = $row[ 'date' ];
344                                 $moving->state_id    = $state[ 'id' ];
345                                 $moving->item_id     = $item[ 'id' ];
346                                 $moving->location_id = $location[ 'id' ];
347                                 $moving->comment     = Yii::t('import', 'Import: {comment}', $row);
348
349                                 if ($moving->validate() && $moving->save())
350                                 {
351                                     // Записаали первое движение
352                                     $arrayReturn[ 'countImported' ]++;
353                                 }
354                                 else
355                                 {
356                                     // Запись не удалась, пробуем удалить предмет/оборудование
357                                     Items::find()->where([ 'id' => $item_id, 'checked' => FALSE ])->one()->delete();
358                                     // Сообщим об ошибке
359                                     $arrayReturn[ 'countErrors' ]++;
360                                     $arrayReturn[ 'errors' ] .= '<br />' . Yii::t('import', 'Moving: {date} (') . $moving->errors['date'][0]. Yii::t('import', '), Inventory number:{invent}, model: {model}, location: {location} ( {region} )' , $row);
361                                 }
362                                 unset($moving);
363                             }
364                         }
365                     }
366                 }
367             }
368         }
369
370         // Возврат результата импорта
371         return $arrayReturn;
372     }
373
374     /**
375      * Импорт данных из файла csv
376      * Структура файла данных при выгрузке из 1С: (Колонки могут меняться.
377      * | № п/п |  | Предмет/оборудование |  |  |  |  |  |  | Инвентарный номер | Материально отвественное лицо |  |  | Место размещения | Регион/подразделение | Количество |
378      * Так как 1С из коробки не умеет выгружать форму в .csv, то приходится сначала выгрузить в .xls(x), и уже из MS Excel/Lible office Calc сохранять в .csv
379      */
380     public function actionImport()
381     {
382         if (! User::canPermission('updateRecord') ) {
383             return $this->redirect(['site/index']);
384         }
385         $model   = new Import();
386         $message = '';
387         $searchModel = new ItemsSearch();
388         $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
389         if (Yii::$app->request->isPost)
390         {
391             $rows = [];
392             $columns = [];
393             $columnsNames = [
394                 'npp'         => Yii::t('import', 'No. in order'),
395                 'model'       => Yii::t('import', 'Primary means'),
396                 'netname'     => Yii::t('import', 'Network name'),
397                 'invent'      => Yii::t('import', 'Inventory number'),
398                 'comment'     => Yii::t('import', 'Financially responsible person'),
399                 'os'          => Yii::t('import', 'Operation system'),
400                 'mac'         => Yii::t('import', 'MAC address'),
401                 'serial'      => Yii::t('import', 'Serial number'),
402                 'product'     => Yii::t('import', 'Product number'),
403                 'modelnumber' => Yii::t('import', 'Model number'),
404                 'date'        => Yii::t('import', 'Date of acceptance for registration'),
405                 'location'    => Yii::t('import', 'Location'),
406                 'region'      => Yii::t('import', 'Region'),
407                 'type'        => Yii::t('import', 'Type'),
408                 'status'      => Yii::t('import', 'State'),
409             ];
410             $model->filecsv = UploadedFile::getInstance($model, 'filecsv');
411             if ($model->upload())
412             {
413                 $fileName = 'upload/' . $model->filecsv->baseName . '.' . $model->filecsv->extension;
414                 $handle = fopen($fileName, 'r');
415                 if ($handle !== FALSE)
416                 {
417                     if (strcasecmp($model->filecsv->extension, 'csv') === 0 )
418                     {
419                         // Построчное чтение CSV файла
420                         while (($row = fgetcsv($handle, 2048, ';')) !== false )
421                         {
422                             // Пока не собраны индексы столбцов из шапки
423                             if (count($columns) == 0)
424                             {
425                                 // Ищем строку с заголовком таблицы
426                                 if ( stripos($row[0], $columnNames[ 'npp' ]) !== FALSE )
427                                 {
428                                     // Перебираем все колонки
429                                     foreach ($row as $key => $item)
430                                     {
431                                         // Перебираем все названия заголовков колонок
432                                         foreach($columnNamses as $name => $text)
433                                         {
434                                             // Если название совпало,
435                                             if (stripos($item, $text) !== FALSE)
436                                             {
437                                                 // Сохраняем индек колонки
438                                                 $columns[ $name ] = $key;
439                                             }
440                                         }
441                                     }
442                                 }
443                             }
444                             else
445                             {
446                                 // Перебираем предметы/оборудование (Номер по порядку должен быть целым числом)
447                                 if (ctype_digit(str_replace(' ', '', $row[ $columns[ 'npp' ]])))
448                                 {
449                                     // Заполняем очередную строку для таблицы
450                                     $line = [];
451                                     foreach ($columns as $key => $index)
452                                     {
453                                         $line[ $key ] = $row[ $index ];
454                                     }
455                                     if (isset($line[ 'date' ]))
456                                     {
457                                         if ($line[ 'date' ] == '#NULL!') $line[ 'date' ] = date('d.m.Y');
458                                     }
459                                     else
460                                     {
461                                         $line[ 'date' ] = date('d.m.Y');
462                                     }
463                                     array_push($rows, $line);
464                                 }
465                             }
466                         } // Перебор строк файла
467                     }
468                     else // xls(x) файлы
469                     {
470                         $inputFileType = \PHPExcel_IOFactory::identify($fileName); // Получение типа данных в файле
471                         $excelReader = \PHPExcel_IOFactory::createReader($inputFileType); // Создание потока чтения из файла
472                         $excelObj = $excelReader->load($fileName); // Открытие файла
473                         $worksheet = $excelObj->getSheet(0);       // Работаем только с первым листом (обычно туда выгружает 1С)
474                         // Индексы ячеек
475
476                         // Цикл по всем строкам
477                         foreach ($worksheet->getRowIterator() as $row)
478                         {
479                             $cellIterator = $row->getCellIterator(); // Получаем итератор ячеек в строке
480                             $cellIterator->setIterateOnlyExistingCells(FALSE); // Указываем проверять даже не установленные ячейки
481
482                             if (count($columns) == 0) // Пока не найдена шапка, проверяем строку
483                             {
484                                 $flag = FALSE;
485                                 foreach ($cellIterator as $key => $item)
486                                 {
487                                     if (($key == 'A') && (stripos($item->getValue(), $columnsNames[ 'npp' ]) !== FALSE)) $flag = TRUE;
488                                     if ($flag)
489                                     {
490                                         foreach ($columnsNames as $name => $text)
491                                         {
492                                             if (stripos($item->getValue(), $text) !== FALSE)
493                                             {
494                                                 $columns[ $name ] = $key;
495                                             }
496                                         }
497                                     }
498                                 }
499                             }
500                             else
501                             {
502                                 $flag = FALSE;
503                                 $line = [];
504                                 foreach ($cellIterator as $key => $item)
505                                 {
506                                     if ($key == $columns[ 'npp' ])
507                                     {
508                                         $npp = str_replace(' ', '', $item->getValue());
509                                         if (ctype_digit($npp)) $flag = TRUE;
510                                     }
511                                     if ($flag)
512                                     {
513                                         foreach($columns as $keym => $index)
514                                         {
515                                             if ($index == $key) $line[ $keym ] = $item->getValue();
516                                         }
517                                     }
518                                 }
519                                 if ($flag)
520                                 {
521                                     if (isset($line[ 'date' ]))
522                                     {
523                                         if ($line[ 'date' ] == '#NULL!') $line[ 'date' ] = date('d.m.Y');
524                                     }
525                                     else
526                                     {
527                                         $line[ 'date' ] = date('d.m.Y');
528                                     }
529                                     array_push($rows, $line);
530                                 }
531                             }
532                         }
533                     }
534                     fclose($handle);
535                     $res = $this->doImport($rows);
536                 }
537                 $message .= Yii::t('items', 'Read {countRows} records.<br />Imported {countImported} Items.<br />Exists {countExists} Items.<br />Error read {countErrors} records.<br />{errors}', $res);
538             }
539         }
540         return $this->render('import',[
541             'message' => $message,
542             'model' => $model,
543             'searchModel' => $searchModel,
544             'dataProvider' => $dataProvider,
545         ]);
546     }
547
548     /**
549      * Показ одного предмета/оборудования. (не используется)
550      * @param integer $id
551      * @return mixed
552      * @throws NotFoundHttpException если предмет/оборудование отсутствует
553      */
554     public function actionView($id)
555     {
556         if (! User::canPermission('updateRecord') ) {
557             return $this->redirect([ 'index', 'id' => $id ]);
558         }
559         return $this->render('view', [
560             'model' => $this->findModel($id),
561         ]);
562     }
563
564     /**
565      * Создание нового предмета/оборудования.
566      * @return mixed
567      */
568     public function actionCreate()
569     {
570         if (! User::canPermission('createRecord') ) {
571             return $this->redirect(['site/index']);
572         }
573         $model = new Items(); // Новый предмет/оборудование
574         $model->checked = true;
575         $modelm = new Moving();
576         if ($model->load(Yii::$app->request->post()) && $model->save())
577         {
578             // Удалось сохранить, создаём первую запись движения
579             if ($modelm->load(Yii::$app->request->post()))
580             {
581                 $modelm->item_id = $model->id;
582                 $modelm->comment = 'Поступление';
583
584                 if ( $modelm->save() ) // Пробуем сохранить движение
585                 {
586                     return $this->redirect([ 'index', 'id' => $model->id ]); // Если удалось, показываем список оборудования
587                 } else
588                 {
589                     $this->findModel($model->id)->delete();  // Иначе удаляем созданную запись предмета/оборудования
590                     unset($model->id);                       // Очищаем идентификатор предмета/оборудования
591                     $model->isNewRecord = true;
592                     return $this->render('create', [         // Показываем форму создания нового предмета/оборудования
593                         'model'  => $model,
594                         'modelm' => $modelm,
595                     ]);
596                 }
597             } else
598             {
599                 $this->findModel($model->id)->delete();  // Иначе удаляем созданную запись предмета/оборудования
600                 unset($model->id);                      // Очищаем идентификатор предмета/оборудования
601                 $model->isNewRecord = true;
602                 return $this->render('create', [        // Показываем форму создания нового предмета/оборудования
603                     'model'  => $model,
604                     'modelm' => $modelm,
605                 ]);
606             }
607         } else // не удалось сохранить - отображаем форму создания нового предмета/оборудования
608         {
609             return $this->render('create', [
610                 'model'  => $model,
611                 'modelm' => $modelm,
612             ]);
613         }
614
615     }
616
617     /**
618      * Изменение существующего предмета/оборудвания.
619      * Если премет/обрудование сохранён, то возвращаемся на страницу списка всех предметов/оборудования.
620      * @param integer $id
621      * @return mixed
622      * @throws NotFoundHttpException если предмет/оборудование отсутствует
623      */
624     public function actionUpdate($id)
625     {
626         if (! User::canPermission('updateRecord') ) {
627             return $this->redirect(['index']);
628         }
629         $model = $this->findModel($id);
630
631         if ($model->load(Yii::$app->request->post()) && $model->save())
632         {
633             return $this->redirect([ 'index', 'id' => $model->id ]);
634         }
635
636         $searchModelM = new MovingSearch([ 'item_id' => $model->id ]);
637         $dataProviderM = $searchModelM->search(Yii::$app->request->queryParams);
638
639          return $this->render('update', [
640             'searchModelM'  => $searchModelM,
641             'dataProviderM' => $dataProviderM,
642             'model'         => $model,
643         ]);
644     }
645
646     /**
647      * Удаляет сушествующий предмет/оборудование.
648      * Если премет/обрудование удалён, то возвращаемся на страницу списка всех предметов/оборудования.
649      * @param integer $id
650      * @return mixed
651      * @throws NotFoundHttpException if the model cannot be found
652      */
653     public function actionDelete($id)
654     {
655         if (! User::canPermission('updateRecord') ) {
656             return $this->redirect(['site/index']);
657         }
658         $this->findModel($id)->delete();
659
660         return $this->redirect([ 'index' ]);
661     }
662
663     /**
664      * Finds the Items model based on its primary key value.
665      * If the model is not found, a 404 HTTP exception will be thrown.
666      * @param integer $id
667      * @return Items the loaded model
668      * @throws NotFoundHttpException если предмет/оборудование отсутствует
669      */
670     protected function findModel($id)
671     {
672         if (($model = Items::findOne($id)) !== null)
673         {
674             return $model;
675         }
676
677         throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
678     }
679 }