]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Merge branch 'develop' into feature_smirnov_erp-88_upload_xlsx
authorAlexander Smirnov <fredeom@mail.ru>
Wed, 7 Aug 2024 07:41:22 +0000 (10:41 +0300)
committerAlexander Smirnov <fredeom@mail.ru>
Wed, 7 Aug 2024 07:41:22 +0000 (10:41 +0300)
# Conflicts:
# erp24/actions/motivation/IndexAction.php
# erp24/composer.json
# erp24/services/MotivationService.php
# erp24/uploads/template_plan.xlsx

1  2 
erp24/actions/motivation/IndexAction.php
erp24/views/motivation/index.php

index 6c5dab83b32ff85b516fff2a7f0b365507d4cdb5,f745fa062253454a944aac23ccc3b4ceb772d390..aa76a2825f9baf6ac2c3525c312ebcdde3382ffa
@@@ -31,13 -40,17 +40,20 @@@ class IndexAction extends Actio
              }
          }
  
          $model = DynamicModel::validateData([
-                 'store_id' => null, 'year' => null, 'month' => null
-             ], [
-                 [['store_id', 'year', 'month'], 'safe']
-             ]);
-         $model->load(Yii::$app->request->get());
+             'store_id' => $currentUser->store_id, // Устанавливаем store_id текущего пользователя
+             'year' => $currentDate->format('Y'), // Текущий год
+             'month' => $currentDate->format('n') // Текущий месяц (1-12)
+         ], [
+             [['store_id', 'year', 'month'], 'safe']
+         ]);
++        $motivations = Motivation::find()->all();
++        $possibleStoreIds = ArrayHelper::getColumn($motivations, 'store_id');
 +
          $motivations = Motivation::find()->all();
          $possibleStoreIds = ArrayHelper::getColumn($motivations, 'store_id');
  
          $years = array_filter(range(2023, 20100), function ($k) use ($possibleYears) {
              return in_array($k, $possibleYears);
          });
+         $years = array_combine($years, $years);
          $possibleMonth = ArrayHelper::getColumn($motivations, 'month');
-         $months = array_filter(['Январь',' Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь'], function ($k, $v) use ($possibleMonth) {
-             return in_array($v + 1, $possibleMonth);
+         $months = array_filter([1 => 'Январь', 2 => 'Февраль', 3 => 'Март', 4 => 'Апрель', 5 => 'Май', 6 => 'Июнь', 7 => 'Июль', 8 => 'Август', 9 => 'Сентябрь', 10 => 'Октябрь', 11 => 'Ноябрь', 12 => 'Декабрь'], function ($k, $v) use ($possibleMonth) {
+             return in_array($v, $possibleMonth);
          }, ARRAY_FILTER_USE_BOTH);
  
-         return $this->controller->render('index',
-             compact('model', 'stores', 'years', 'months'));
+         // Загружаем данные из GET-запроса, если они есть
+         if (Yii::$app->request->get()) {
+             $model->load(Yii::$app->request->get());
+             if ($model->year === '') {
+                 $model->year = $currentDate->format('Y');
+             } else {
+                 $model->year = intval($model->year);
+                 // Проверяем, что год находится в допустимом диапазоне
+                 if (!in_array($model->year, $years)) {
+                     $model->year = $currentDate->format('Y');
+                 }
+             }
+             $model->month = intval($model->month);
+         }
+         $showTable = false;
+         $motivationData = [];
+         $daysInMonth = null;
+         $daysInLastWeek = null;
+         $week5Header = 'Неделя 5';
+         if ($model->store_id !== null && $model->year !== null && $model->month !== null) {
+             $showTable = true;
+             $motivationService = new MotivationService();
+             // получаем данные из таблицы
+             $motivationDataTableSort = $motivationService->getMotivationDataTableSort($model->store_id, $model->year, $model->month);
+             // Получаем количество дней в месяце
+             $daysInMonth = cal_days_in_month(CAL_GREGORIAN, $model->month, $model->year);
+             // Определяем, сколько дней в последней неделе
+             $daysInLastWeek = $daysInMonth - 28;
+             // Список названий строк, для которых нужно выполнить расчет
+             $calculateFor = [
 -                
++
+                 '12', //'Аренда'
+                 '13', //'Коммунальные услуги'
+                 '14', //'Охрана'
+                 '16', //'Доставка до клиента курьер'
+                 '17', //'Доставка до клиента такси'
+                 '22', //'Техническое обслуживание кассовых аппаратов'
+                 '23', //'Интернет'
+                 '27', // 'Бухгалтерские услуги: постановка и ведение БУ и НУ'
+                 '28', //'Юридические услуги'
+                 '29', //'Кадровое администрирование, охрана труда'
+                 '30', //'Услуги по подбору персонала'
+                 '31', //'Администрирование ИТ инфраструктуры (подключения к базам данных, ПО, почта, интернет)'
+                 '32', //'Лицензия на ПО: ERP система'
+                 '33' //'Продвижение и продажа товара через сайт'
+             ];
+             // Проходим по всем данным и выполняем расчеты для каждой недели
+             foreach ($motivationDataTableSort as &$row) {
+                 if (!key_exists('code', $row)){
+                     continue;
+                 }
+                 if (in_array($row['code'], $calculateFor)) {
+                     $row['week1'] = $this->calculateWeekValue($row['plan'], $daysInMonth, 7);
+                     $row['week2'] = $this->calculateWeekValue($row['plan'], $daysInMonth, 7);
+                     $row['week3'] = $this->calculateWeekValue($row['plan'], $daysInMonth, 7);
+                     $row['week4'] = $this->calculateWeekValue($row['plan'], $daysInMonth, 7);
+                     // Для 5-й недели используем оставшиеся дни
+                     if ($daysInLastWeek > 0) {
+                         $row['week5'] = $this->calculateWeekValue($row['plan'], $daysInMonth, $daysInLastWeek);
+                     } else {
+                         $row['week5'] = null;
+                     }
+                 }
+             }
+             // Формируем заголовок для 5-й недели
+             if ($model->month == 2) { // Февраль
+                 if ($daysInMonth == 29) {
+                     $week5Header = 'Неделя 5<br>(29)';
+                 }
+             } else if ($daysInLastWeek > 0) {
+                 $week5Header = "Неделя 5<br>(29-{$daysInMonth})";
+             }
+         }
+         return $this->controller->render(
+             'index',
+             compact('model', 'stores', 'years', 'months', 'motivationDataTableSort', 'showTable',
+                 'daysInMonth', 'daysInLastWeek', 'week5Header')
+         );
+     }
+     // Функция для расчета значения недели
+     private function calculateWeekValue($plan, $daysInMonth, $daysInWeek)
+     {
+         // Проверяем, является ли план пустым или нулевым
+         if (empty($plan) || $plan === null) {
+             return null;
+         }
+         // Проверяем, чтобы избежать деления на ноль
+         if ($daysInMonth == 0) {
+             return null;
+         }
+         return ($plan / $daysInMonth) * $daysInWeek;
      }
- }
+ }
index 5a91c9052eb01c485696b1ca66dc7e616e84b384,38386efcadefcf479a0a223c760884edfa182d43..b2e27e424e2a09145d657d28c89a6c024926b209
@@@ -9,7 -10,13 +10,15 @@@ use yii_app\records\MotivationCostsItem
  /** @var $stores array */
  /** @var $years array */
  /** @var $months array */
+ /** @var $motivationDataTableSort array */
+ /** @var $showTable bool */
+ /** @var $daysInMonth int */
+ /** @var $daysInLastWeek int */
+ /** @var $week5Header string */
++$this->registerJsFile('/js/motivation/index.js', ['position' => \yii\web\View::POS_END]);
 +
  $this->registerJsFile('/js/motivation/index.js', ['position' => \yii\web\View::POS_END]);
  
  ?>
                          'pluginOptions' => [
                              'allowClear' => true
                          ],
-                     ])->label(false) ?></div>
+                     ])->label(false) ?>
+                 </div>
+                 <div class="d-flex justify-content-around align-items-center gap-2">
+                     <div class="mb-3">Месяц:</div>
+                     <div style="display: inline-block">
+                         <?= $form->field($model, 'month')->widget(Select2::class, [
+                             'data' => $months,
+                             'language' => 'ru',
+                             'options' => ['placeholder' => 'Месяц...'],
+                             'pluginOptions' => [
+                                 'allowClear' => true
+                             ],
+                         ])->label(false) ?>
+                     </div>
+                 </div>
+                 <div class="d-flex justify-content-around align-items-center gap-2">
+                     <div class="mb-3"><?= Html::submitButton('Применить', ['class' => 'btn btn-secondary btn-sm']) ?></div>
+                 </div>
              </div>
              <div class="d-flex justify-content-around align-items-center gap-2">
-                 <div class="mb-3">Месяц:</div>
-                 <div style="display: inline-block"><?= $form->field($model, 'month')->widget(Select2::class, [
-                         'data' => $months,
-                         'language' => 'ru',
-                         'options' => ['placeholder' => 'Месяц...'],
-                         'pluginOptions' => [
-                             'allowClear' => true
-                         ],
-                     ])->label(false) ?></div>
-             </div>
-             <div class="d-flex justify-content-around align-items-center gap-2">
-                 <div class="mb-3"><?= Html::submitButton('Применить', ['class' => 'btn btn-secondary btn-sm'])?></div>
+                 <div class="mb-3"><?= Html::button('Загрузка плановых значений', ['class' => 'btn btn-success btn-sm',
+                         'onclick' => 'openUploadDictionary();'])?></div>
              </div>
 +            <div class="d-flex justify-content-around align-items-center gap-2">
 +                <div class="mb-3"><?= Html::button('Загрузка плановых значений', ['class' => 'btn btn-success btn-sm',
 +                        'onclick' => 'openUploadDictionary();'])?></div>
 +            </div>
          </div>
-     </div>
  
-     <?php ActiveForm::end() ?>
+         <?php ActiveForm::end() ?>
+         <?php if ($showTable) : ?>
+             <?php if (empty($motivationDataTableSort)) : ?>
+                 <div class="alert alert-info mt-3">Данные отсутствуют</div>
+             <?php else : ?>
+                 <?php
+                 // Функция для расчета значения недели
+                 function calculateWeekValue($plan, $daysInMonth, $daysInWeek)
+                 {
+                     return ($plan / $daysInMonth) * $daysInWeek;
+                 }
+                 ?>
+                 <h3 class="mt-3">
+                     Магазин: <?= $stores[$model->store_id] ?? '' ?>,
+                     Год: <?= $model->year ?>,
+                     Месяц: <?= $months[$model->month] ?? '' ?>
+                 </h3>
+                 <?= GridView::widget([
+                     'dataProvider' => new \yii\data\ArrayDataProvider([
+                         'allModels' => array_filter($motivationDataTableSort, function ($item) {
+                             return !in_array($item['name'], [
+                                 'Услуги агентов (тариф)',
+                                 'Кадровое администрирование, охрана труда (тариф)',
+                                 'Базовая премия',
+                                 'Размер бонуса',
+                                 'Пороговый коэффициент'
+                             ]);
+                         }),
+                         'pagination' => false,
+                     ]),
+                     'floatHeader' => true,
+                     'columns' => [
+                         [
+                             'attribute' => 'name',
+                             'header' => 'Наименование статьи доходов/расходов',
+                         ],
+                         [
+                             'attribute' => 'plan',
+                             'value' => function ($model) {
+                                 if ($model["plan"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["plan"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                             'header' => 'План',
+                         ],
+                         [
+                             'attribute' => 'correction',
+                             'value' => function ($model) {
+                                 if ($model["correction"] !== null && $model["correction"] !== '') {
+                                     return Yii::$app->formatter->asDecimal($model["correction"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                             'header' => 'Корректировка',
+                         ],
+                         [
+                             'attribute' => 'week1',
+                             'class' => 'kartik\grid\FormulaColumn',
+                             'header' => 'Неделя 1<br>(1-7)',
+                             'value' => function ($model) {
+                                 if ($model["week1"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["week1"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'week2',
+                             'class' => 'kartik\grid\FormulaColumn',
+                             'header' => 'Неделя 2<br>(8-14)',
+                             'value' => function ($model) {
+                                 if ($model["week2"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["week2"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'week3',
+                             'class' => 'kartik\grid\FormulaColumn',
+                             'header' => 'Неделя 3<br>(15-21)',
+                             'value' => function ($model) {
+                                 if ($model["week3"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["week3"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'week4',
+                             'class' => 'kartik\grid\FormulaColumn',
+                             'header' => 'Неделя 4<br>(22-28)',
+                             'value' => function ($model) {
+                                 if ($model["week4"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["week4"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'week5',
+                             'class' => 'kartik\grid\FormulaColumn',
+                             'header' => $week5Header,
+                             'value' => function ($model) {
+                                 if ($model["week5"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["week5"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'forecast',
+                             'header' => 'Прогноз за месяц',
+                             'value' => function ($model) {
+                                 if ($model["forecast"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["forecast"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'fact',
+                             'header' => 'Факт за месяц',
+                             'value' => function ($model) {
+                                 if ($model["fact"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["fact"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ],
+                         [
+                             'attribute' => 'deviation',
+                             'header' => 'Отклонение, %',
+                             'value' => function ($model) {
+                                 if ($model["deviation"] !== null) {
+                                     return Yii::$app->formatter->asDecimal($model["deviation"], 2);
+                                 } else {
+                                     return " ";
+                                 }
+                             },
+                         ]
+                     ],
+                     'rowOptions' => function ($model, $key, $index, $grid) {
+                         $style = '';
+                         $class = '';
+                         switch ($model['name']) {
+                             case 'Выручка от реализации':
+                                 $style = 'font-weight: 700; background-color:#f7caac;';
+                                 $class = 'fw-bold';
+                                 break;
+                             case 'Прочие услуги':
+                             case 'Продажа товара':
+                             case 'Чистая прибыль':
+                             case 'Рентабельность по чистой прибыли, %':
+                                 $style = 'font-weight: bold; background-color:#a5a5a5;';
+                                 break;
+                             case 'Прямые расходы на продажу':
+                             case 'Операционные расходы (Себестоимость)':
+                             case 'Общехозяйственные расходы':
+                                 $style = 'font-weight: bold; background-color:#ccffff;';
+                                 break;
+                             case 'Маржинальный доход':
+                             case 'Валовая прибыль':
+                                 $style = 'font-weight: bold; background-color:#c5e0b3;';
+                                 break;
+                                 // Добавьте другие case для остальных специфических строк
+                             default:
+                                 // Проверка для остальных строк, которые должны иметь жирный шрифт
+                                 $boldRows = [
+                                     'Стоимость товара', 'Услуги агентов (Расходы на закупку, хранение, доставку товара)',
+                                     'Брак, пересорт', 'Расходные материалы (обеспечение продаж)', 'Оплата труда', 'Содержание помещения',
+                                     'Расходы по доставке', 'Услуги маркетплейсов', 'Содержание и обслуживание ОС и НМА',
+                                     'Услуги связи', 'Прочие операционные расходы', 'Бухгалтерия и финансы',
+                                     'Юридическое сопровождение', 'HR- услуги', 'IT услуги',
+                                     'Продвижение и продажа товара через сайт', 'Минимальный порог Чистой прибыли, руб.',
+                                     'Расчет премии'
+                                 ];
+                                 if (in_array($model['name'], $boldRows)) {
+                                     $style = 'font-weight: 700;';
+                                 }
+                                 break;
+                         }
+                         return ['class' => $class, 'style' => $style];
+                     },
+                     'responsive' => true,
+                     'hover' => true
+                 ]); ?>
+                 <h3 class="mt-3">
+                     Основные единицы для расчета
+                 </h3>
+                 <?= GridView::widget([
+                     'dataProvider' => new \yii\data\ArrayDataProvider([
+                         'allModels' => array_filter($motivationDataTableSort, function ($item) {
+                             return in_array($item['name'], [
+                                 'Услуги агентов (тариф)',
+                                 'Кадровое администрирование, охрана труда (тариф)',
+                                 'Базовая премия',
+                                 'Размер бонуса',
+                                 'Пороговый коэффициент'
+                             ]);
+                         }),
+                         'pagination' => false,
+                     ]),
+                     'floatHeader' => true,
+                     'columns' => [
+                         [
+                             'attribute' => 'name',
+                             'header' => 'Наименование',
+                             'value' => function ($model) {
+                                 $mappings = [
+                                     'Услуги агентов (тариф)' => 'Услуги агентов - тариф',
+                                     'Кадровое администрирование, охрана труда (тариф)' => 'Кадровое администрирование, охрана труда',
+                                 ];
+                                 return isset($mappings[$model['name']]) ? $mappings[$model['name']] : $model['name'];
+                             },
+                         ],
+                         [
+                             'attribute' => 'plan',
+                             'header' => 'Значение',
+                             'format' => ['decimal', 2],
+                         ],
+                     ],
+                     'responsive' => true,
+                     'hover' => true
+                 ]); ?>
+             <?php endif; ?>
+         <?php endif; ?>
  
- </div>
+     
+     </div>