OSDN Git Service

bfa3c5eafaf9f819660313d0c8b263d0034c6f93
[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
22 /**
23  * ItemsController implements the CRUD actions for Items model.
24  */
25 class ItemsController extends Controller
26 {
27     /**
28      * {@inheritdoc}
29      */
30     public function behaviors()
31     {
32         return [
33             'verbs' => [
34                 'class'   => VerbFilter::className(),
35                 'actions' => [
36                     'delete' => [ 'POST' ],
37                 ],
38             ],
39         ];
40     }
41
42     /**
43      * Добавление предмета/оборудование если его нет
44      * @param array $options
45      *        string 'invent'
46      *        string 'model'
47      *        string 'comment'
48      *        integer|NULL 'type_id'
49      *        string|NULL 'typeName'
50      *        string|NULL 'name'
51      *        string|NULL 'os'
52      *        string|NULL 'mac'
53      *        string|NULL 'serial'
54      *        string|NULL 'product'
55      *        string|NULL 'modelnum'
56      * @return integer|FALSE
57      */
58     public static function addIfNeed($options)
59     {
60         if (is_array($options) && isset($options[ 'invent' ]))
61         {
62             $item = Items::find()
63                 ->where([ 'like', 'invent', $options[ 'invent' ]]);
64             if (isset($options[ 'serial' ])) {
65                 $item = $item->andWhere([ 'like', 'serial', $options[ 'serial' ]]);
66             }
67             $item = $item->all();
68
69             if (count($item) > 0)
70             {
71                 return $item[0]->id;
72             }
73             if (isset($options[ 'model' ]))
74             {
75                 if (isset($options[ 'typeName' ]))
76                 {
77                     $type_id = TypesController::addIfNeed($options[ 'typeName' ]);
78                     if($type_id === FALSE)
79                     {
80                         $type_id = NULL;
81                     }
82                 }
83                 else
84                 {
85                     $type_id = isset($options[ 'type_id' ]) ? $options[ 'type_id' ] : NULL;
86                 }
87                 $item = new Items();
88                 $item->name        = isset($options[ 'name' ]) ? $options[ 'name' ] : NULL;
89                 $item->model       = isset($options[ 'model' ]) ? $options[ 'model' ] : NULL;
90                 $item->invent      = isset($options[ 'invent' ]) ? $options[ 'invent' ] : NULL;
91                 $item->comment     = isset($options[ 'comment' ]) ? $options[ 'comment' ] : NULL;
92                 $item->type_id     = $type_id;
93                 $item->os          = isset($options[ 'os' ]) ? $options[ 'os' ] : NULL;
94                 $item->mac         = isset($options[ 'mac' ]) ? $options[ 'mac' ] : NULL;
95                 $item->serial      = isset($options[ 'serial' ]) ? $options[ 'serial' ] : NULL;
96                 $item->product     = isset($options[ 'product' ]) ? $options[ 'product' ] : NULL;
97                 $item->modelnumber = isset($options[ 'modelnumber' ]) ? $options[ 'modelnumber' ] : NULL;
98                 $item->checked     = false;
99
100                 if ($item->validate() && $item->save())
101                 {
102                     return $item->id;
103                 }
104             }
105         }
106         return FALSE;
107     }
108
109     /**
110      * Формирование PDF файла для печати QR-кодов для наклеек
111      * @param integer|array|null id
112      * @return mixed
113      */
114     public function actionPrint()
115     {
116         if (! User::canPermission('takingInventory') ) {
117             return $this->redirect(['site/index']);
118         }
119         // Список предметов/оборудования, если есть
120         $id = Yii::$app->request->get('id');
121
122         $models = Items::find();
123         if (isset($id))
124             if (is_array($id))
125             {
126                 $models = $models->where([ 'in', 'id', $id ]); // Несколько предметов/оборудования
127             } else
128             {
129                 $models = $models->where([ 'id' => $id ]); // Один предмет/оборудование
130             }
131         $models = $models->all(); // Формирование списка
132
133         $pdf = Yii::$app->pdf; // Pабота с PDF
134
135         $pdf->methods[ 'SetHeader' ] = ''; // Yii::t('items', 'Items');
136         $pdf->methods[ 'SetFooter' ] = ''; // ['{PAGENO}'];
137         // Границы листа
138         $pdf->marginLeft   = 5;
139         $pdf->marginRight  = 5;
140         $pdf->marginTop    = 9;
141         $pdf->marginBottom = 15;
142         // Имя файла для выгрузки, по умолчанию document.pdf
143         $pdf->filename     = Yii::t('app', Yii::$app->name) . ' (' . Yii::t('items', 'Items') . ').pdf';
144
145         // Заполнение страницы данными
146         $pdf->content = $this->renderPartial('print', [ 'models' => $models ]);
147
148         // Выгрузка PDF
149         return $pdf->render();
150     }
151
152     /**
153      * Процедура начала инвентаризации.
154      * @return mixed
155      */
156     public function actionStart_checking()
157     {
158         if (! User::canPermission('takingInventory') ) {
159             return $this->redirect(['site/index']);
160         }
161         // Запрос на получение списка идентификаторов предметов/оборудования, которые списаны
162         $modelS = Moving::find()
163             ->select('item_id')
164             ->joinWith('status')
165             ->Where([ 'ilike', Status::tableName() . '.name', 'Списано' ]);
166
167         // Получаем список всех предметов/оборудования, кроме списанного
168         $model = Items::find()
169             ->select('id')
170             ->innerJoin([ 'm' => $modelS ], 'not m.item_id = id')
171             ->all();
172
173         // Устанавливаем флаг непроинвентаризированных для всех предметов/оборудования из полученного списка.
174         Items::updateAll([ 'checked' => false ], [ 'in', 'id', $model ]);
175
176         // Переход к списку предметов/оборудования.
177         return $this->redirect([ 'index' ]);
178     }
179
180     /**
181      * Инвентаризация
182      * @param string|null $qrcheck считанный QR-код
183      * @return mixed
184      */
185      public function actionCheck()
186      {
187         //*
188         if (! User::canPermission('takingInventory') ) {
189             return $this->redirect(['site/index']);
190         } // */
191         $model = new Check();
192         $message = '';
193         if ($model->load(Yii::$app->request->post()))
194         {
195             if ((! empty($model->qrcheck)) && strpos($model->qrcheck, ',') !== false)
196             {
197                 $keys = explode(',', $model->qrcheck);
198                 Items::updateAll([ 'checked' => true ], [ 'invent' => trim($keys[ 0 ]), 'serial' => trim($keys[ 1 ]) ]);
199                 $items = Items::find()->where([ 'invent' => trim($keys[ 0 ]), 'serial' => trim($keys[ 1 ]) ])->all();
200                 //$message = '[0] = "' . $keys[0] . '", [1] = "' . $keys[1] . '"<br />';
201                 foreach ($items as $row)
202                 {
203                     $message .= $row->model . ' (' . $row->id . ')';
204                 }
205                 if ($message != '')
206                     $message = Yii::t('items', 'Checked item(s): ') . $message;
207                 $model->qrcheck = '';
208             }
209         }
210         $searchModel = new ItemsSearch();
211         $dataProvider = $searchModel->noinvent($model);
212
213         return $this->render('check', [
214             'message'      => $message,
215             'model'        => $model,
216             'searchModel'  => $searchModel,
217             'dataProvider' => $dataProvider,
218         ]);
219      }
220
221     /**
222      * Список всех предметов/оборудования.
223      * @return mixed
224      */
225     public function actionIndex()
226     {
227         if (! User::canPermission('createRecord') ) {
228             return $this->redirect(['site/index']);
229         }
230         $searchModel = new ItemsSearch();
231         $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
232
233         return $this->render('index', [
234             'searchModel' => $searchModel,
235             'dataProvider' => $dataProvider,
236         ]);
237     }
238
239     /**
240      * Импорт данных из файла csv
241      * Структура файла данных при выгрузке из 1С:
242      * | № п/п |  | Предмет/оборудование |  |  |  |  |  |  | Инвентарный номер | Материально отвественное лицо |  |  | Место размещения | Регион/подразделение | Количество |
243      * | 0     | 1| 2                    | 3| 4| 5| 6| 7| 8| 9                 |10                             |11|12|13                |14                    |15          |
244      * Так как 1С из коробки не умеет выгружать форму в .csv, то приходится сначала выгрузить в .xls(x), и уже из MS Excel/Lible office Calc сохранять в .csv
245      */
246     public function actionImport()
247     {
248         if (! User::canPermission('updateRecord') ) {
249             return $this->redirect(['site/index']);
250         }
251         $model   = new Import();
252         $count   = 0;
253         $counti  = 0;
254         $skip    = 0;
255         $existi  = 0;
256         $errors  = '';
257         $message = '';
258         $searchModel = new ItemsSearch();
259         $dataProvider = $searchModel->search(Yii::$app->request->queryParams);
260         if (Yii::$app->request->isPost)
261         {
262             $model->filecsv = UploadedFile::getInstance($model, 'filecsv');
263             if ($model->upload())
264             {
265                 $handle = fopen('upload/' . $model->filecsv->baseName . '.' . $model->filecsv->extension, 'r');
266                 if ($handle !== FALSE)
267                 {
268                     while (($row = fgetcsv($handle, 1024, ';')) !== false )
269                     {
270                         if (intval($row[ 0 ]) . '' == $row[ 0 ])
271                         {
272                             $location = $row[ 13 ];
273                             $region   = $row[ 14 ];
274                             $count++;
275                             $location_id = LocationsController::addIfNeed([ 'name' => $location, 'region' => $region ]);
276                             if ($location_id !== FALSE)
277                             {
278                                 $invent  = $row[ 9 ];
279                                 if (count(Items::find()->where([ 'like', 'invent', $invent ])->all()) == 0)
280                                 {
281                                     $model_  = $row[ 2 ];
282                                     $comment = Yii::t('moving', 'Imported. {comment}', [ 'comment' => $row[ 10 ] ]);
283                                     $item_id = $this::addIfNeed([ 'invent' => $invent, 'model' => $model_, 'comment' => $comment ]);
284                                     if ( $item_id !== FALSE)
285                                     {
286                                         $date = date('d.m.Y');
287                                         $state_id = StatusController::addIfNeed([ 'name' => 'Склад' ]);
288                                         if ($state_id === FALSE)
289                                         {
290                                             $state_id = NULL;
291                                         } // Состояние предмета/оборудование
292
293                                         $moving = new Moving();
294                                         $moving->date = $date;
295                                         $moving->item_id = $item_id;
296                                         $moving->state_id = $state_id;
297                                         $moving->location_id = $location_id;
298                                         $moving->comment = $comment;
299                                         if ($moving->validate() && $moving->save())
300                                         {
301                                             $counti++;
302                                         } // Добавление перемещение
303                                         else
304                                         {
305                                             Items::find([ 'id' => $item_id ])->delete();
306                                             $skip++;
307                                             $errors .= '<br>Движение: ' . implode(';', $row);
308                                         } // Не удалось добавить перемещение
309                                     }
310                                 } // Предмет/оборудование добавлено
311                                 else
312                                 {
313                                     $existi++;
314                                 } // Предмет/оборудование уже есть
315                             }
316                             else
317                             {
318                                 $skip++;
319                                 $errors .= '<br>Место расположения: ' . implode(';', $row);
320                             } // не удалось найти или добавить место размещения
321                         } // Строка с данными
322                     } // Перебор строк файла
323                     fclose($handle);
324                 }
325                 $message .= Yii::t('items', 'Read {count} records.<br />Imported {counti} Items.<br />Exists {exist} Items.<br />Error read {skip} records.<br />{errors}', 
326                     [ 'counti' => $counti, 'count' => $count, 'exist' => $existi, 'skip' => $skip, 'errors' => $errors ]);
327             }
328         }
329         return $this->render('import',[
330             'message' => $message,
331             'model' => $model,
332             'searchModel' => $searchModel,
333             'dataProvider' => $dataProvider,
334         ]);
335     }
336
337     /**
338      * Показ одного предмета/оборудования. (не используется)
339      * @param integer $id
340      * @return mixed
341      * @throws NotFoundHttpException если предмет/оборудование отсутствует
342      */
343     public function actionView($id)
344     {
345         if (! User::canPermission('updateRecord') ) {
346             return $this->redirect(['index']);
347         }
348         return $this->render('view', [
349             'model' => $this->findModel($id),
350         ]);
351     }
352
353     /**
354      * Создание нового предмета/оборудования.
355      * @return mixed
356      */
357     public function actionCreate()
358     {
359         if (! User::canPermission('createRecord') ) {
360             return $this->redirect(['site/index']);
361         }
362         $model = new Items(); // Новый предмет/оборудование
363         $model->checked = true;
364         $modelm = new Moving();
365         if ($model->load(Yii::$app->request->post()) && $model->save())
366         {
367             // Удалось сохранить, создаём первую запись движения
368             if ($modelm->load(Yii::$app->request->post()))
369             {
370                 $modelm->item_id = $model->id;
371                 $modelm->comment = 'Поступление';
372
373                 if ( $modelm->save() ) // Пробуем сохранить движение
374                 {
375                     return $this->redirect([ 'index', 'id' => $model->id ]); // Если удалось, показываем список оборудования
376                 } else
377                 {
378                     $this->findModel($model->id)->delete();  // Иначе удаляем созданную запись предмета/оборудования
379                     unset($model->id);                       // Очищаем идентификатор предмета/оборудования
380                     $model->isNewRecord = true;
381                     return $this->render('create', [         // Показываем форму создания нового предмета/оборудования
382                         'model'  => $model,
383                         'modelm' => $modelm,
384                     ]);
385                 }
386             } else
387             {
388                 $this->findModel($model->id)->delete();  // Иначе удаляем созданную запись предмета/оборудования
389                 unset($model->id);                      // Очищаем идентификатор предмета/оборудования
390                 $model->isNewRecord = true;
391                 return $this->render('create', [        // Показываем форму создания нового предмета/оборудования
392                     'model'  => $model,
393                     'modelm' => $modelm,
394                 ]);
395             }
396         } else // не удалось сохранить - отображаем форму создания нового предмета/оборудования
397         {
398             return $this->render('create', [
399                 'model'  => $model,
400                 'modelm' => $modelm,
401             ]);
402         }
403
404     }
405
406     /**
407      * Изменение существующего предмета/оборудвания.
408      * Если премет/обрудование сохранён, то возвращаемся на страницу списка всех предметов/оборудования.
409      * @param integer $id
410      * @return mixed
411      * @throws NotFoundHttpException если предмет/оборудование отсутствует
412      */
413     public function actionUpdate($id)
414     {
415         if (! User::canPermission('updateRecord') ) {
416             return $this->redirect(['index']);
417         }
418         $model = $this->findModel($id);
419
420         if ($model->load(Yii::$app->request->post()) && $model->save())
421         {
422             return $this->redirect([ 'index', 'id' => $model->id ]);
423         }
424
425         $searchModelM = new MovingSearch([ 'item_id' => $model->id ]);
426         $dataProviderM = $searchModelM->search(Yii::$app->request->queryParams);
427
428          return $this->render('update', [
429             'searchModelM'  => $searchModelM,
430             'dataProviderM' => $dataProviderM,
431             'model'         => $model,
432         ]);
433     }
434
435     /**
436      * Удаляет сушествующий предмет/оборудование.
437      * Если премет/обрудование удалён, то возвращаемся на страницу списка всех предметов/оборудования.
438      * @param integer $id
439      * @return mixed
440      * @throws NotFoundHttpException if the model cannot be found
441      */
442     public function actionDelete($id)
443     {
444         if (! User::canPermission('updateRecord') ) {
445             return $this->redirect(['site/index']);
446         }
447         $this->findModel($id)->delete();
448
449         return $this->redirect([ 'index' ]);
450     }
451
452     /**
453      * Finds the Items model based on its primary key value.
454      * If the model is not found, a 404 HTTP exception will be thrown.
455      * @param integer $id
456      * @return Items the loaded model
457      * @throws NotFoundHttpException если предмет/оборудование отсутствует
458      */
459     protected function findModel($id)
460     {
461         if (($model = Items::findOne($id)) !== null)
462         {
463             return $model;
464         }
465
466         throw new NotFoundHttpException(Yii::t('app', 'The requested page does not exist.'));
467     }
468 }