}
}
+
$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;
}
- }
+ }
/** @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>