]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
Merge branch 'develop' into feature_smirnov_erp-140_fact_motivation
authorAlexander Smirnov <fredeom@mail.ru>
Thu, 29 Aug 2024 12:38:23 +0000 (15:38 +0300)
committerAlexander Smirnov <fredeom@mail.ru>
Thu, 29 Aug 2024 12:38:23 +0000 (15:38 +0300)
# Conflicts:
# erp24/services/MotivationService.php
# erp24/views/motivation/index.php

1  2 
erp24/actions/motivation/IndexAction.php
erp24/records/MotivationCostsItem.php
erp24/services/MotivationService.php
erp24/views/motivation/index.php

Simple merge
index 65f870e788f9795a1055e26a369495fe4ca0f78d,dad9f984a2f4633096e88db4f08ea093f8c3b0b6..f8d543daea50e92f632e01a6cbdeafdd9fce558a
@@@ -5,7 -5,7 +5,8 @@@ namespace yii_app\services
  use Yii;
  use PhpOffice\PhpSpreadsheet\IOFactory;
  use yii\helpers\Json;
 +use yii_app\records\EmployeePayment;
+ use yii_app\records\AdminGroup;
  use yii_app\records\ExportImportTable;
  use yii\helpers\ArrayHelper;
  use yii_app\records\Motivation;
@@@ -22,8 -22,78 +23,73 @@@ use yii_app\records\TimetableFactModel
  use yii_app\records\Timetable;
  
  
 -
 -
 -use yii_app\records\EmployeePayment;
 -
 -
  class MotivationService
  {
+     const  CODE_OFFLINE_SALES = 1;
+     const CODE_ONLINE_SALES = 2;
+     const CODE_ASSEMBLY_SERVICES = 3;
+     const CODE_DELIVERY_SERVICES = 4;
+     const CODE_DELIVERY_DEFECTS = 6;
+     const CODE_WRITE_OFF_ILLIQUID_GOODS_SPOOLAGE_EXPIRATION_OF_SHELF_LIFE = 7;
+     const CODE_EQUIPMENT_FAILURE_DEFECT = 8;
+     const CODE_REGRADING = 9;
+     const CODE_CONSUMABLES_SALES_SUPPORT = 10;
+     const CODE_RENT = 12;
+     const CODE_PUBLIC_SERVICES = 13;
+     const CODE_SECURITY = 14;
+     const CODE_CLEANING_SERVICES_FOR_PREMISES_AND_TERRITORY = 15;
+     const CODE_DELIVERY_TO_CLIENT_CURRIER = 16;
+     const CODE_DELIVERY_TO_CLIENT_TAXI = 17;
+     const CODE_MARKETPLACE_SERVICES = 18;
+     const CODE_REFRIGERATION_EQUIPMENT_REPAIR_MAINTANANCE = 19;
+     const CODE_COSTS_FOR_MAINTENANCE_AND_REPAIR_OF_OFFICE_EQUIPMENT_INCLUDING_CONSUMABLES = 20;
+     const CODE_EXPENSES_FOR_MAINENANCE_AND_REPAIR_OF_OTHER_FIXED_ASSETS = 21;
+     const CODE_MAINTENANCE_OF_CASH_REGISTERS = 22;
+     const CODE_INTERNET = 23;
+     const CODE_HOUSEHOLD_GOODS = 24;
+     const CODE_STATIONARY = 25;
+     const CODE_ACCOUNTING_SERVICES_SETTING_UP_AND_MAINTAINING_ACCOUNTING_AND_TAX_RECORDS = 27;
+     const CODE_LEGAL_SERVICES = 28;
+     const CODE_PERSONAL_ADMINISTRATION_LABOR_PROTECTION = 29;
+     const CODE_RECRUITMENT_SERVICES = 30;
+     const CODE_ADMINISTRATION_OF_IT_INFRASTRUCTURE_CONNECTIONS_TO_DATABASES_SOFTWARE_MAIL_INTERNET = 31;
+     const CODE_SOFTWARE_LICENSE_ERP_SYSTEM = 32;
+     const CODE_PROMOTION_AND_SALE_OF_GOODS_THROUGH_THE_WEBSITE = 33;
+     const CODE_PERSONAL_ADMINISTRATION_LABOR_PROTECTION_TARIFF = 36;
+     const CODE_BASE_BONUS = 37;
+     const CODE_BONUS_SIZE = 38;
+     const CODE_AGENT_SERVICES_TARIFF = 35;
+     const CODE_NUMBER_OF_EMPLOYEES = 34;
+     const CODE_PAYROLL_FUND = 11;
+     const CODE_THRESHOLD_COEFFICIENT = 39;
+     const CODE_DRINKING_WATER = 26;
+     const CODE_COSTS_OF_GOODS = 5;
+     const CODE_REVENUE_FROM_SALES = 1001;
+     const CODE_SALE_OF_GOODS = 1002;
+     const CODE_OTHER_SERVICES = 1003;
+     const CODE_DIRECT_SELLING_COSTS = 1004;
+     const CODE_COST_PRICE_OF_GOODS = 1005;
+     const CODE_AGENT_SERVICES_EXPENSES_FOR_PURCHASING_STORING_DELIVERING_GOODS = 1006;
+     const CODE_DEFECT_RESORTING = 1007;
+     const CODE_MARGINAL_INCOME = 1008;
+     const CODE_OPERATIONAL_EXPANSES_COST = 1009;
+     const CODE_PAYMENT = 1010;
+     const CODE_MAINTENANCE_OF_PRIMISES = 1011;
+     const CODE_DELIVERY_COST = 1012;
+     const CODE_MAINTENANCE_AND_SERVICE_OF_FIXED_ASSETS_AND_INTANGIBLE_ASSETS = 1013;
+     const CODE_COMMUNICATION_SERVICES = 1014;
+     const CODE_OTHER_OPERATING_EXPENSES = 1015;
+     const CODE_GROSS_PROFIT = 1016;
+     const CODE_GENERAL_BUSINESS_EXPENSES = 1017;
+     const CODE_ACCOUNTING_AND_FINANCE = 1018;
+     const CODE_LEGAL_SUPPORT = 1019;
+     const CODE_HR_SERVICES = 1020;
+     const CODE_IT_SERVICES = 1021;
+     const CODE_NET_PROFIT = 1022;
+     const CODE_NET_PROFIT_MARGIN_PERCENT = 1023;
+     const CODE_NET_PROFIT_THRESHOLD_RUB = 1024;
+     const CODE_CALCULATION_OF_PREMIUM = 1025;
  
      // 6. Создание массива дополнительных элементов
      static $additionalItems = [
          return $weeks;
      }
  
 +    public static function getMotivationValue($motivation_id, $group_id, $value_id) {
 +        $value = 0;
 +        $motivationValue = MotivationValue::find()->where(['motivation_id' => $motivation_id,
 +            'motivation_group_id' => $group_id, 'value_id' => $value_id])->one();
 +        /** @var $motivationValue MotivationValue */
 +        if ($motivationValue) {
 +            switch ($motivationValue->value_type) {
 +                case MotivationCostsItem::DATA_TYPE_INT: { $value = $motivationValue->value_int; break; }
 +                default: { $value = $motivationValue->value_float; break;}
 +            }
 +        }
 +        return $value;
 +    }
 +
 +    public static function calculateMonthSales($year, $month) {
 +        $monthStart = date("Y-m-d 00:00:00", strtotime($year . '-' . $month . '-1'));
 +        $monthEnd = date("Y-m-t 23:59:59", strtotime($year . '-' . $month . '-1'));
 +
 +        $sales = Sales::find()->where(['between', 'date', $monthStart, $monthEnd])
 +            ->andWhere(['operation' => Sales::OPERATION_SALE])
 +            ->asArray()->all();
 +        $salesIds = ArrayHelper::getColumn($sales, 'id');
 +
 +        // Ищем чеки-возврат на текущие чеки
 +        $returnSales = Sales::find()->where(['operation' => Sales::OPERATION_RETURN, 'sales_check' => $salesIds])->all();
 +        $returnSalesIds = ArrayHelper::getColumn($returnSales, 'sales_check');
 +
 +        $salesOffline = Sales::find()->select(['SUM(summ) as total', 'store_id'])
 +            ->where(['between', 'date', $monthStart, $monthEnd])
 +            ->andWhere(['operation' => Sales::OPERATION_SALE])
 +            ->andWhere(['order_id' => ['', '0']])
 +            ->andWhere(['NOT IN', 'id', $returnSalesIds])
 +            ->groupBy(['store_id'])
 +            ->indexBy('store_id')
 +            ->asArray()->all();
 +
 +        $salesOnline = Sales::find()->select(['SUM(summ) as total', 'store_id'])
 +            ->where(['between', 'date', $monthStart, $monthEnd])
 +            ->andWhere(['operation' => Sales::OPERATION_SALE])
 +            ->andWhere(['NOT IN', 'order_id', ['', '0']])
 +            ->andWhere(['NOT IN', 'id', $returnSalesIds])
 +            ->groupBy(['store_id'])
 +            ->indexBy('store_id')
 +            ->asArray()->all();
 +
 +        $motivations = Motivation::find()->where(['year' => $year, 'month' => $month])->indexBy('store_id')->all();
 +
 +        $motivationValueGroupFact = MotivationValueGroup::find()->where(['alias' => 'fact'])->one();
 +        $motivationCostsItemOffline = MotivationCostsItem::find()->where(['name' => 'Оффлайн продажи'])->one();
 +        $motivationCostsItemOnline = MotivationCostsItem::find()->where(['name' => 'Онлайн продажи'])->one();
 +        /** @var $motivationCostsItemOffline MotivationCostsItem */
 +        /** @var $motivationCostsItemOnline MotivationCostsItem */
 +
 +
 +        $storeIds = ArrayHelper::getColumn(CityStore::find()->where(['visible' => '1'])->all(), 'id');
 +        foreach ($storeIds as $store_id) {
 +            if (isset($motivations[$store_id])) {
 +                $correction = self::getMotivationValue($motivations[$store_id]->id, 8, $motivationCostsItemOffline->code);
 +
 +                $motivationValueOffline = MotivationValue::find()->where(['motivation_id' => $motivations[$store_id]->id,
 +                    'motivation_group_id' => $motivationValueGroupFact->id, 'value_id' => $motivationCostsItemOffline->code])->one();
 +                if (!$motivationValueOffline) {
 +                    $motivationValueOffline = new MotivationValue;
 +                    $motivationValueOffline->motivation_id = $motivations[$store_id]->id;
 +                    $motivationValueOffline->motivation_group_id = $motivationValueGroupFact->id;
 +                    $motivationValueOffline->value_id = $motivationCostsItemOffline->code;
 +                    $motivationValueOffline->value_type = $motivationCostsItemOffline->data_type;
 +                }
 +                $motivationValueOffline->value_float = ($salesOffline[$store_id]['total'] ?? 0) + $correction;
 +                $motivationValueOffline->save();
 +                if ($motivationValueOffline->getErrors()) {
 +                    throw new \Exception(Json::encode($motivationValueOffline->getErrors()));
 +                }
 +
 +                $correction = self::getMotivationValue($motivations[$store_id]->id, 8, $motivationCostsItemOnline->code);
 +
 +                $motivationValueOnline = MotivationValue::find()->where(['motivation_id' => $motivations[$store_id]->id,
 +                    'motivation_group_id' => $motivationValueGroupFact->id, 'value_id' => $motivationCostsItemOnline->code])->one();
 +                if (!$motivationValueOnline) {
 +                    $motivationValueOnline = new MotivationValue;
 +                    $motivationValueOnline->motivation_id = $motivations[$store_id]->id;
 +                    $motivationValueOnline->motivation_group_id = $motivationValueGroupFact->id;
 +                    $motivationValueOnline->value_id = $motivationCostsItemOnline->code;
 +                    $motivationValueOnline->value_type = $motivationCostsItemOnline->data_type;
 +                }
 +                $motivationValueOnline->value_float = ($salesOnline[$store_id]['total'] ?? 0) + $correction;
 +                $motivationValueOnline->save();
 +                if ($motivationValueOnline->getErrors()) {
 +                    throw new \Exception(Json::encode($motivationValueOnline->getErrors()));
 +                }
 +            }
 +        }
 +    }
 +
 +    public static function calculateMonthServices($year, $month) {
 +        $monthStart = date("Y-m-d 00:00:00", strtotime($year . '-' . $month . '-1'));
 +        $monthEnd = date("Y-m-t 23:59:59", strtotime($year . '-' . $month . '-1'));
 +
 +        // Ищем каталог-гуиды категории services
 +        $productsClass = ProductsClass::find()->select(['category_id', 'tip'])
 +            ->where(['tip' => 'services'])
 +            ->indexBy('category_id')
 +            ->asArray()->all();
 +
 +        // Ищем продуктовые гуиды по каталог-гуидам категории service
 +        $products1c = Products1c::find()->select(['id', 'parent_id', 'name'])
 +            ->where(['parent_id' => array_keys($productsClass), 'tip' => 'products'])
 +            ->indexBy(['id'])
 +            ->asArray()->all();
 +
 +        // Ищем каталог-гуиды категории services_delivery
 +        $productsClassDelivery = ProductsClass::find()->select(['category_id', 'tip'])
 +            ->where(['tip' => 'services_delivery'])
 +            ->indexBy('category_id')
 +            ->asArray()->all();
 +
 +        // Ищем продуктовые гуиды по каталог-гуидам категории service_delivery
 +        $products1cDelivery = Products1c::find()->select(['id', 'parent_id', 'name'])
 +            ->where(['parent_id' => array_keys($productsClassDelivery), 'tip' => 'products'])
 +            ->indexBy(['id'])
 +            ->asArray()->all();
 +
 +        // Ищем продажи по продуктовым гуидам по каталог-гуидам категории service
 +        $sales = Sales::find()->alias('s')
 +            ->leftJoin('sales_products p', 'p.check_id = s.id')
 +            ->where(['between', 's.date', $monthStart, $monthEnd])
 +            ->andWhere(['p.product_id' => array_keys($products1c)])
 +            ->andWhere(['s.operation' => Sales::OPERATION_SALE])
 +            ->asArray()->all();
 +        $salesIds = ArrayHelper::getColumn($sales, 'id');
 +
 +        // Ищем чеки-возврат на текущие чеки
 +        $returnSales = Sales::find()->where(['operation' => Sales::OPERATION_RETURN, 'sales_check' => $salesIds])->all();
 +        $returnSalesIds = ArrayHelper::getColumn($returnSales, 'sales_check');
 +
 +        // Ищем продукты из категории services
 +        $salesProduct = SalesProducts::find()->alias('p')
 +            ->select(['SUM(p.summ) as total', 'store_id'])
 +            ->leftJoin('sales s', 's.id = p.check_id')
 +            ->where(['check_id' => $salesIds])
 +            ->andWhere(['NOT IN', 'check_id', $returnSalesIds])
 +            ->andWhere(['product_id' => array_keys($products1c)])
 +            ->groupBy(['store_id'])
 +            ->indexBy('store_id')
 +            ->asArray()->all();
 +
 +        // Ищем продажи по продуктовым гуидам по каталог-гуидам категории services_delivery
 +        $salesDelivery = Sales::find()->alias('s')
 +            ->leftJoin('sales_products p', 'p.check_id = s.id')
 +            ->where(['between', 's.date', $monthStart, $monthEnd])
 +            ->andWhere(['p.product_id' => array_keys($products1cDelivery)])
 +            ->andWhere(['s.operation' => Sales::OPERATION_SALE])
 +            ->asArray()->all();
 +        $salesIdsDelivery = ArrayHelper::getColumn($salesDelivery, 'id');
 +
 +        // Ищем чеки-возврат на текущие чеки
 +        $returnSalesDelivery = Sales::find()->where(['operation' => Sales::OPERATION_RETURN, 'sales_check' => $salesIdsDelivery])->all();
 +        $returnSalesIdsDelivery = ArrayHelper::getColumn($returnSalesDelivery, 'sales_check');
 +
 +        // Ищем продукты из категории services_delivery
 +        $salesProductDelivery = SalesProducts::find()->alias('p')
 +            ->select(['SUM(p.summ) as total', 'store_id'])
 +            ->leftJoin('sales s', 's.id = p.check_id')
 +            ->where(['check_id' => $salesIdsDelivery])
 +            ->andWhere(['NOT IN', 'check_id', $returnSalesIdsDelivery])
 +            ->andWhere(['product_id' => array_keys($products1cDelivery)])
 +            ->groupBy(['store_id'])
 +            ->indexBy('store_id')
 +            ->asArray()->all();
 +
 +        $motivations = Motivation::find()->where(['year' => $year, 'month' => $month])->indexBy('store_id')->all();
 +
 +        $motivationValueGroupFact = MotivationValueGroup::find()->where(['alias' => 'fact'])->one();
 +        $motivationCostsItemServices = MotivationCostsItem::find()->where(['name' => 'Услуги по сборке'])->one();
 +        $motivationCostsItemServicesDelivery = MotivationCostsItem::find()->where(['name' => 'Услуги по доставке'])->one();
 +        /** @var $motivationCostsItemServices MotivationCostsItem */
 +        /** @var $motivationCostsItemServicesDelivery MotivationCostsItem */
 +
 +        $storeIds = ArrayHelper::getColumn(CityStore::find()->where(['visible' => '1'])->all(), 'id');
 +        foreach ($storeIds as $store_id) {
 +            if (isset($motivations[$store_id])) {
 +                $correction = self::getMotivationValue($motivations[$store_id]->id, 8, $motivationCostsItemServices->code);
 +
 +                $motivationValueService = MotivationValue::find()->where(['motivation_id' => $motivations[$store_id]->id,
 +                    'motivation_group_id' => $motivationValueGroupFact->id, 'value_id' => $motivationCostsItemServices->code])->one();
 +                if (!$motivationValueService) {
 +                    $motivationValueService = new MotivationValue;
 +                    $motivationValueService->motivation_id = $motivations[$store_id]->id;
 +                    $motivationValueService->motivation_group_id = $motivationValueGroupFact->id;
 +                    $motivationValueService->value_id = $motivationCostsItemServices->code;
 +                    $motivationValueService->value_type = $motivationCostsItemServices->data_type;
 +                }
 +                $motivationValueService->value_float = ($salesProduct[$store_id]['total'] ?? 0) + $correction;
 +                $motivationValueService->save();
 +                if ($motivationValueService->getErrors()) {
 +                    throw new \Exception(Json::encode($motivationValueService->getErrors()));
 +                }
 +
 +                $correction = self::getMotivationValue($motivations[$store_id]->id, 8, $motivationCostsItemServicesDelivery->code);
 +
 +                $motivationValueServiceDelivery = MotivationValue::find()->where(['motivation_id' => $motivations[$store_id]->id,
 +                    'motivation_group_id' => $motivationValueGroupFact->id, 'value_id' => $motivationCostsItemServicesDelivery->code])->one();
 +                if (!$motivationValueServiceDelivery) {
 +                    $motivationValueServiceDelivery = new MotivationValue;
 +                    $motivationValueServiceDelivery->motivation_id = $motivations[$store_id]->id;
 +                    $motivationValueServiceDelivery->motivation_group_id = $motivationValueGroupFact->id;
 +                    $motivationValueServiceDelivery->value_id = $motivationCostsItemServicesDelivery->code;
 +                    $motivationValueServiceDelivery->value_type = $motivationCostsItemServicesDelivery->data_type;
 +                }
 +                $motivationValueServiceDelivery->value_float = ($salesProductDelivery[$store_id]['total'] ?? 0) + $correction;
 +                $motivationValueServiceDelivery->save();
 +                if ($motivationValueServiceDelivery->getErrors()) {
 +                    throw new \Exception(Json::encode($motivationValueServiceDelivery->getErrors()));
 +                }
 +            }
 +        }
 +    }
 +
 +    public static function calculateMonthDefect($year, $month) {
 +        $monthStart = date("Y-m-d 00:00:00", strtotime($year . '-' . $month . '-1'));
 +        $monthEnd = date("Y-m-t 23:59:59", strtotime($year . '-' . $month . '-1'));
 +
 +        $motivations = Motivation::find()->where(['year' => $year, 'month' => $month])->indexBy('store_id')->all();
 +        $motivationValueGroup = MotivationValueGroup::find()->where(['alias' => 'fact'])->one();
 +        $exportImportTables = ExportImportTable::find()->select(['export_val', 'entity_id'])->where(['entity' => 'city_store',
 +            'entity_id' => array_keys($motivations), 'export_id' => 1])->indexBy('entity_id')->all();
 +        /** @var $exportImportTables ExportImportTable[] */
 +
 +        foreach ($exportImportTables as $store_id => $store_guid) {
 +            if (isset($motivations[$store_id])) {
 +                $writeOffs = WriteOffs::find()->select(['sum(summ) as total', 'type'])
 +                    ->where(['between', 'date', $monthStart, $monthEnd])
 +                    ->andWhere(['store_id' => $store_guid])
 +                    ->groupBy(['type'])
 +                    ->indexBy('type')
 +                    ->asArray()->all();
 +                foreach (MotivationCostsItem::writeOffsToMotivationItemArray() as $key => $motivationItemType) {
 +                    $data = $writeOffs[$key] ?? [];
 +                    $motivationCostsItem = MotivationCostsItem::find()->where(['name' => $motivationItemType])->one();
 +                    /** @var $motivationCostsItem MotivationCostsItem */
 +
 +                    $correction = self::getMotivationValue($motivations[$store_id]->id, 8, $motivationCostsItem->code);
 +
 +                    $motivationValue = MotivationValue::find()->where(['motivation_id' => $motivations[$store_id]->id,
 +                        'motivation_group_id' => $motivationValueGroup->id, 'value_id' => $motivationCostsItem->code])->one();
 +                    if (!$motivationValue) {
 +                        $motivationValue = new MotivationValue;
 +                        $motivationValue->motivation_id = $motivations[$store_id]->id;
 +                        $motivationValue->motivation_group_id = $motivationValueGroup->id;
 +                        $motivationValue->value_id = $motivationCostsItem->code;
 +                        $motivationValue->value_type = $motivationCostsItem->data_type;
 +                    }
 +                    $motivationValue->value_float = ($data['total'] ?? 0) + $correction;
 +                    $motivationValue->save();
 +                    if ($motivationValue->getErrors()) {
 +                        throw new \Exception(Json::encode($motivationValue->getErrors()));
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    public static function calculateMonthSalary($year, $month) {
 +        $monthStart = date("Y-m-d 00:00:00", strtotime($year . '-' . $month . '-1'));
 +        $monthEnd = date("Y-m-t 23:59:59", strtotime($year . '-' . $month . '-1'));
 +
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $store_id = $motivation->store_id;
 +            $monthlyTotalSalary = self::calculateTotalSalary(date("Y-m-d", strtotime($monthStart)), date("Y-m-d", strtotime($monthEnd)), $store_id);
 +
 +            $correction = self::getMotivationValue($motivation->id, 8, 11);
 +
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 11, "float", $monthlyTotalSalary + $correction);
 +        }
 +    }
 +
 +    public static function calculateMonthDeliveryCurier($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $correction = self::getMotivationValue($motivation->id, 8, 16);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 16, "float", $correction);
 +        }
 +    }
 +
 +    public static function calculateMonthAccauntingAndTax($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $plan = self::getMotivationValue($motivation->id, 7, 27);
 +            $adjustment = self::getMotivationValue($motivation->id, 8, 27);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 27, "float", $plan + $adjustment);
 +        }
 +    }
 +
 +    public static function calculateMonthLegalServices($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $plan = self::getMotivationValue($motivation->id, 7, 28);
 +            $adjustment = self::getMotivationValue($motivation->id, 8, 28);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 28, "float", $plan + $adjustment);
 +        }
 +    }
 +
 +    public static function calculateMonthPersonalAdministrationLaborProtection($year, $month) {
 +        $monthStart = date("Y-m-d 00:00:00", strtotime($year . '-' . $month . '-1'));
 +        $monthEnd = date("Y-m-t 23:59:59", strtotime($year . '-' . $month . '-1'));
 +
 +        $timetableFactModels = TimetableFactModel::find()->select(['COUNT(DISTINCT(admin_id)) as cnt', 'store_id'])
 +            ->where(['!=', 'admin_group_id', '45'])
 +            ->andWhere(['between', 'date_shift', $monthStart, $monthEnd])
 +            ->groupBy(['store_id'])
 +            ->indexBy('store_id')
 +            ->asArray()->all();
 +
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            /** @var $motivation Motivation */
 +            $tariff = self::getMotivationValue($motivation->id, 7, 36);
 +            $adjustment = self::getMotivationValue($motivation->id, 8, 36);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 29, "float", $tariff * ($timetableFactModels[$motivation->store_id]['cnt'] ?? 0) + $adjustment);
 +        }
 +    }
 +
 +    public static function calculateMonthAdministrationOfItInfrastructureConnectionsToDatabasesSoftwareMailInternet($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $plan = self::getMotivationValue($motivation->id, 7, 31);
 +            $adjustment = self::getMotivationValue($motivation->id, 8, 31);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 31, "float", $plan + $adjustment);
 +        }
 +    }
 +
 +    public static function calculateMonthSoftwareLicenseErpSystem($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $plan = self::getMotivationValue($motivation->id, 7, 32);
 +            $adjustment = self::getMotivationValue($motivation->id, 8, 32);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 32, "float", $plan + $adjustment);
 +        }
 +    }
 +
 +    public static function calculateMonthCeoAndSaleOfWebsiteGoods($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        foreach ($motivations as $motivation) {
 +            $correction = self::getMotivationValue($motivation->id, 8, 33);
 +            self::saveOrUpdateMotivationValue($motivation->id,
 +                "fact", 33, "float", $correction);
 +        }
 +    }
 +
 +    public static function initMonth1cFields($year, $month) {
 +        $motivations = Motivation::find()
 +            ->where(['year' => $year, 'month' => $month])
 +            ->all();
 +
 +        $valueIdIndices = [12, 13, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 30];
 +
 +        foreach ($motivations as $motivation) {
 +            foreach ($valueIdIndices as $index) {
 +                self::saveOrUpdateMotivationValue($motivation->id, "fact", $index, "float", 0);
 +            }
 +        }
 +    }
++
+     public static function calculateFactFormula($motivationDataTableSort, $year, $month) {
+         // Определяем последний день месяца
+         $lastDayOfMonth = date('t', strtotime("$year-$month-01"));
+         $indMap = [];
+         foreach ($motivationDataTableSort as $ind => $row) {
+             if (!key_exists('code', $row)) {
+                 continue;
+             }
+             $indMap[intval($row['code'])] = $ind;
+         }
+         foreach (range(0,7) as $ind) {
+             switch ($ind) {
+                 case 0: { $column = 'plan'; break; }
+                 case 6: { $column = 'fact'; break; }
+                 case 7: { $column = 'forecast'; break; }
+                 default: { $column = 'week' . $ind; break; }
+             }
+             $motivationDataTableSort[$indMap[self::CODE_SALE_OF_GOODS]][$column] =       // "Продажа товара"
+                 $motivationDataTableSort[$indMap[self::CODE_OFFLINE_SALES]][$column] +   // "Оффлайн продажи"
+                 $motivationDataTableSort[$indMap[self::CODE_ONLINE_SALES]][$column] + 0; // "Онлайн продажи"
+             $motivationDataTableSort[$indMap[self::CODE_OTHER_SERVICES]][$column] =           // "Прочие услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_ASSEMBLY_SERVICES]][$column] +    // "Услуги по сборке"
+                 $motivationDataTableSort[$indMap[self::CODE_DELIVERY_SERVICES]][$column] + 0; // "Услуги по доставке"
+             $motivationDataTableSort[$indMap[self::CODE_REVENUE_FROM_SALES]][$column] = // "Выручка от реализации"
+                 $motivationDataTableSort[$indMap[self::CODE_SALE_OF_GOODS]][$column] +  // "Продажа товара"
+                 $motivationDataTableSort[$indMap[self::CODE_OTHER_SERVICES]][$column] + 0; // "Прочие услуги"
+             $motivationDataTableSort[$indMap[self::CODE_COST_PRICE_OF_GOODS]][$column] = // "Себестоимость товара"
+                 $motivationDataTableSort[$indMap[self::CODE_COSTS_OF_GOODS]][$column] + 0; // "Стоимость товара"
+             $motivationDataTableSort[$indMap[self::CODE_AGENT_SERVICES_EXPENSES_FOR_PURCHASING_STORING_DELIVERING_GOODS]][$column] = // "Услуги агентов (Расходы на закупку, хранение, доставку товара)"
+                 (
+                     $motivationDataTableSort[$indMap[self::CODE_COST_PRICE_OF_GOODS]][$column] + // "Себестоимость товара"
+                     $motivationDataTableSort[$indMap[self::CODE_DEFECT_RESORTING]][$column] // "Брак, пересорт"
+                 ) *
+                 $motivationDataTableSort[$indMap[self::CODE_AGENT_SERVICES_TARIFF]][$column]; // "Услуги агентов (тариф)"
+             $motivationDataTableSort[$indMap[self::CODE_DEFECT_RESORTING]][$column] = // "Брак, пересорт"
+                 $motivationDataTableSort[$indMap[self::CODE_DELIVERY_DEFECTS]][$column] + // "Брак с поставки"
+                 $motivationDataTableSort[$indMap[self::CODE_WRITE_OFF_ILLIQUID_GOODS_SPOOLAGE_EXPIRATION_OF_SHELF_LIFE]][$column] + // "Списание неликвидного товара: порча, истечение срока годности"
+                 $motivationDataTableSort[$indMap[self::CODE_EQUIPMENT_FAILURE_DEFECT]][$column] + // "Брак из-за поломки оборудования"
+                 $motivationDataTableSort[$indMap[self::CODE_REGRADING]][$column] + 0; // "Пересорт"
+             $motivationDataTableSort[$indMap[self::CODE_DIRECT_SELLING_COSTS]][$column] = // "Прямые расходы на продажу"
+                 $motivationDataTableSort[$indMap[self::CODE_COST_PRICE_OF_GOODS]][$column] + // "Себестоимость товара"
+                 $motivationDataTableSort[$indMap[self::CODE_AGENT_SERVICES_EXPENSES_FOR_PURCHASING_STORING_DELIVERING_GOODS]][$column] + // "Услуги агентов (Расходы на закупку, хранение, доставку товара)"
+                 $motivationDataTableSort[$indMap[self::CODE_DEFECT_RESORTING]][$column] + // "Брак, пересорт"
+                 $motivationDataTableSort[$indMap[self::CODE_CONSUMABLES_SALES_SUPPORT]][$column] + 0; // "Расходные материалы (обеспечение продаж)"
+             $motivationDataTableSort[$indMap[self::CODE_MARGINAL_INCOME]][$column] = // "Маржинальный доход"
+                 $motivationDataTableSort[$indMap[self::CODE_REVENUE_FROM_SALES]][$column] - // "Выручка от реализации"
+                 $motivationDataTableSort[$indMap[self::CODE_DIRECT_SELLING_COSTS]][$column] + 0; // "Прямые расходы на продажу"
+             $motivationDataTableSort[$indMap[self::CODE_PAYMENT]][$column] = // "Оплата труда"
+                 $motivationDataTableSort[$indMap[self::CODE_PAYROLL_FUND]][$column] + 0; // "Фонд оплаты труда персонала"
+             $motivationDataTableSort[$indMap[self::CODE_MAINTENANCE_OF_PRIMISES]][$column] = // "Содержание помещения"
+                 $motivationDataTableSort[$indMap[self::CODE_RENT]][$column] + // "Аренда"
+                 $motivationDataTableSort[$indMap[self::CODE_PUBLIC_SERVICES]][$column] + // "Коммунальные услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_SECURITY]][$column] + // "Охрана"
+                 $motivationDataTableSort[$indMap[self::CODE_CLEANING_SERVICES_FOR_PREMISES_AND_TERRITORY]][$column] + 0; // "Услуги по уборке помещений и территории"
+             $motivationDataTableSort[$indMap[self::CODE_DELIVERY_COST]][$column] = // "Расходы по доставке"
+                 $motivationDataTableSort[$indMap[self::CODE_DELIVERY_TO_CLIENT_CURRIER]][$column] + // "Доставка до клиента курьер"
+                 $motivationDataTableSort[$indMap[self::CODE_DELIVERY_TO_CLIENT_TAXI]][$column] + 0; // "Доставка до клиента такси"
+             $motivationDataTableSort[$indMap[self::CODE_MAINTENANCE_AND_SERVICE_OF_FIXED_ASSETS_AND_INTANGIBLE_ASSETS]][$column] = // "Содержание и обслуживание ОС и НМА"
+                 $motivationDataTableSort[$indMap[self::CODE_REFRIGERATION_EQUIPMENT_REPAIR_MAINTANANCE]][$column] + // "Холодильное оборудование (ремонт, содержание, ТО)"
+                 $motivationDataTableSort[$indMap[self::CODE_COSTS_FOR_MAINTENANCE_AND_REPAIR_OF_OFFICE_EQUIPMENT_INCLUDING_CONSUMABLES]][$column] + // "Расходы на содержание и ремонт оргтехники, в т.ч. расходные материалы"
+                 $motivationDataTableSort[$indMap[self::CODE_EXPENSES_FOR_MAINENANCE_AND_REPAIR_OF_OTHER_FIXED_ASSETS]][$column] + // "Расходы на содержание и ремонт прочих ОС"
+                 $motivationDataTableSort[$indMap[self::CODE_MAINTENANCE_OF_CASH_REGISTERS]][$column] + 0; // "Техническое обслуживание кассовых аппаратов"
+             $motivationDataTableSort[$indMap[self::CODE_COMMUNICATION_SERVICES]][$column] = // "Услуги связи"
+                 $motivationDataTableSort[$indMap[self::CODE_INTERNET]][$column] + 0; // "Интернет"
+             $motivationDataTableSort[$indMap[self::CODE_OTHER_OPERATING_EXPENSES]][$column] = // "Прочие операционные расходы"
+                 $motivationDataTableSort[$indMap[self::CODE_HOUSEHOLD_GOODS]][$column] + // "Хозяйственные товары"
+                 $motivationDataTableSort[$indMap[self::CODE_STATIONARY]][$column] + // "Канцтовары"
+                 $motivationDataTableSort[$indMap[self::CODE_DRINKING_WATER]][$column] + 0; // "Вода питьевая"
+             $motivationDataTableSort[$indMap[self::CODE_OPERATIONAL_EXPANSES_COST]][$column] = // "Операционные расходы (Себестоимость)"
+                 $motivationDataTableSort[$indMap[self::CODE_PAYMENT]][$column] + // "Оплата труда"
+                 $motivationDataTableSort[$indMap[self::CODE_MAINTENANCE_OF_PRIMISES]][$column] + // "Содержание помещения"
+                 $motivationDataTableSort[$indMap[self::CODE_DELIVERY_COST]][$column] + // "Расходы по доставке"
+                 $motivationDataTableSort[$indMap[self::CODE_MARKETPLACE_SERVICES]][$column] + // "Услуги маркетплейсов"
+                 $motivationDataTableSort[$indMap[self::CODE_MAINTENANCE_AND_SERVICE_OF_FIXED_ASSETS_AND_INTANGIBLE_ASSETS]][$column] + // "Содержание и обслуживание ОС и НМА"
+                 $motivationDataTableSort[$indMap[self::CODE_COMMUNICATION_SERVICES]][$column] + // "Услуги связи"
+                 $motivationDataTableSort[$indMap[self::CODE_OTHER_OPERATING_EXPENSES]][$column] + 0; // "Прочие операционные расходы"
+             $motivationDataTableSort[$indMap[self::CODE_GROSS_PROFIT]][$column] = // "Валовая прибыль"
+                 $motivationDataTableSort[$indMap[self::CODE_MARGINAL_INCOME]][$column] - // "Маржинальный доход"
+                 $motivationDataTableSort[$indMap[self::CODE_OPERATIONAL_EXPANSES_COST]][$column] + 0; // "Операционные расходы (Себестоимость)"
+             $motivationDataTableSort[$indMap[self::CODE_ACCOUNTING_AND_FINANCE]][$column] = // "Бухгалтерия и финансы"
+                 $motivationDataTableSort[$indMap[self::CODE_ACCOUNTING_SERVICES_SETTING_UP_AND_MAINTAINING_ACCOUNTING_AND_TAX_RECORDS]][$column] + 0; // "Бухгалтерские услуги: постановка и ведение БУ и НУ"
+             $motivationDataTableSort[$indMap[self::CODE_LEGAL_SUPPORT]][$column] = // "Юридическое сопровождение"
+                 $motivationDataTableSort[$indMap[self::CODE_LEGAL_SERVICES]][$column] + 0; // "Юридические услуги"
+             $motivationDataTableSort[$indMap[self::CODE_HR_SERVICES]][$column] = // "HR- услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_PERSONAL_ADMINISTRATION_LABOR_PROTECTION]][$column] + // "Кадровое администрирование, охрана труда"
+                 $motivationDataTableSort[$indMap[self::CODE_RECRUITMENT_SERVICES]][$column] + 0; // "Услуги по подбору персонала"
+             $motivationDataTableSort[$indMap[self::CODE_IT_SERVICES]][$column] = // "IT услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_ADMINISTRATION_OF_IT_INFRASTRUCTURE_CONNECTIONS_TO_DATABASES_SOFTWARE_MAIL_INTERNET]][$column] + // "Администрирование ИТ инфраструктуры (подключения к базам данных, ПО, почта, интернет)"
+                 $motivationDataTableSort[$indMap[self::CODE_SOFTWARE_LICENSE_ERP_SYSTEM]][$column] + 0; // "Лицензия на ПО: ERP система"
+             $motivationDataTableSort[$indMap[self::CODE_GENERAL_BUSINESS_EXPENSES]][$column] = // "Общехозяйственные расходы"
+                 $motivationDataTableSort[$indMap[self::CODE_ACCOUNTING_AND_FINANCE]][$column] + // "Бухгалтерия и финансы"
+                 $motivationDataTableSort[$indMap[self::CODE_LEGAL_SUPPORT]][$column] + // "Юридическое сопровождение"
+                 $motivationDataTableSort[$indMap[self::CODE_HR_SERVICES]][$column] + // "HR- услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_IT_SERVICES]][$column] + // "IT услуги"
+                 $motivationDataTableSort[$indMap[self::CODE_PROMOTION_AND_SALE_OF_GOODS_THROUGH_THE_WEBSITE]][$column] + 0; // "Продвижение и продажа товара через сайт"
+             $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT]][$column] = // "Чистая прибыль"
+                 $motivationDataTableSort[$indMap[self::CODE_GROSS_PROFIT]][$column] - // "Валовая прибыль"
+                 $motivationDataTableSort[$indMap[self::CODE_GENERAL_BUSINESS_EXPENSES]][$column] + 0; // "Общехозяйственные расходы"
+             $c5 = $motivationDataTableSort[$indMap[self::CODE_REVENUE_FROM_SALES]][$column]; // "Выручка от реализации"
+             if ($c5 != 0) {
+                 $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_MARGIN_PERCENT]][$column] = // "Рентабельность по чистой прибыли, %"
+                     $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT]][$column] / $c5; // "Чистая прибыль"
+             }
+             if ($ind == 0) {
+                 $b62 = $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT]]["plan"]; // "Чистая прибыль"
+                 if ($b62 > 0) {
+                     $b64 = $b62 * 0.9;
+                 } else {
+                     $b64 = $b62 * 1.1;
+                 }
+                 $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]]["plan"] = $b64; // "Минимальный порог Чистой прибыли, руб."
+             }
+             if ($ind >= 1 && $ind <= 4) {
+                 $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]][$column] = // "Минимальный порог Чистой прибыли, руб."
+                     $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]]["plan"] / $lastDayOfMonth * 7; // "Минимальный порог Чистой прибыли, руб."
+             }
+             if ($ind == 5) {
+                 $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]][$column] = // "Минимальный порог Чистой прибыли, руб."
+                     $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]]["plan"] / $lastDayOfMonth * ($lastDayOfMonth - 4 * 7); // "Минимальный порог Чистой прибыли, руб."
+             }
+             if ($ind == 7) {
+                 $sum = 0;
+                 foreach (range(1, 5) as $index) {
+                     $sum += $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]]['week' . $index]; // "Минимальный порог Чистой прибыли, руб."
+                 }
+                 $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]][$column] = $sum; // "Минимальный порог Чистой прибыли, руб."
+             }
+ //            if ($ind > 0) {
+ //                $c62 = $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT]][$column]; // "Чистая прибыль"
+ //                $b64 = $motivationDataTableSort[$indMap[self::CODE_NET_PROFIT_THRESHOLD_RUB]][$ind == 6 ? "plan" : $column]; // "Минимальный порог Чистой прибыли, руб."
+ //
+ //                $j66 = 0;
+ //                if ($c62 >= $b64) {
+ //                    $formula = $c62 - $c5 * $motivationDataTableSort[$indMap[self::CODE_THRESHOLD_COEFFICIENT]]["plan"]; // "Пороговый коэффициент"
+ //                    if ($formula > 0) {
+ //                        $j66 = $formula;
+ //                    }
+ //                }
+ //                $motivationDataTableSort[$indMap[self::CODE_CALCULATION_OF_PREMIUM]][$column] = $j66 + 0; // "Расчет премии"
+ //            }
+         }
+         // Отклонение
+         $deviationFunc = function ($code) use(&$motivationDataTableSort, &$indMap) {
+             if ($motivationDataTableSort[$indMap[$code]]["plan"] != 0) {
+                 $motivationDataTableSort[$indMap[$code]]["deviation"] =
+                     $motivationDataTableSort[$indMap[$code]]["fact"] /
+                     $motivationDataTableSort[$indMap[$code]]["plan"];
+             }
+         };
+ //        $names = [
+ //            "Выручка от реализации",
+ //            "Продажа товара",
+ //            "Оффлайн продажи",
+ //            "Онлайн продажи",
+ //            "Прочие услуги",
+ //            "Услуги по сборке",
+ //            "Услуги по доставке",
+ //            "Прямые расходы на продажу",
+ //            "Себестоимость товара",
+ //            "Услуги агентов (Расходы на закупку, хранение, доставку товара)",
+ //            "Брак, пересорт",
+ //            "Брак с поставки",
+ //            "Списание неликвидного товара: порча, истечение срока годности",
+ //            "Брак из-за поломки оборудования",
+ //            "Пересорт",
+ //            "Расходные материалы (обеспечение продаж)",
+ //            "Маржинальный доход",
+ //            "Операционные расходы (Себестоимость)",
+ //            "Оплата труда",
+ //            "Фонд оплаты труда персонала",
+ //            "Содержание помещения",
+ //            "Аренда",
+ //            "Коммунальные услуги",
+ //            "Охрана",
+ //            "Услуги по уборке помещений и территории",
+ //            "Расходы по доставке",
+ //            "Доставка до клиента курьер",
+ //            "Доставка до клиента такси",
+ //            "Услуги маркетплейсов",
+ //            "Содержание и обслуживание ОС и НМА",
+ //            "Холодильное оборудование (ремонт, содержание, ТО)",
+ //            "Расходы на содержание и ремонт оргтехники, в т.ч. расходные материалы",
+ //            "Расходы на содержание и ремонт прочих ОС",
+ //            "Техническое обслуживание кассовых аппаратов",
+ //            "Услуги связи",
+ //            "Интернет",
+ //            "Прочие операционные расходы",
+ //            "Хозяйственные товары",
+ //            "Канцтовары",
+ //            "Вода питьевая",
+ //            "Валовая прибыль",
+ //            "Общехозяйственные расходы",
+ //            "Бухгалтерия и финансы",
+ //            "Бухгалтерские услуги: постановка и ведение БУ и НУ",
+ //            "Юридическое сопровождение",
+ //            "Юридические услуги",
+ //            "HR- услуги",
+ //            "Кадровое администрирование, охрана труда",
+ //            "Услуги по подбору персонала",
+ //            "IT услуги",
+ //            "Администрирование ИТ инфраструктуры (подключения к базам данных, ПО, почта, интернет)",
+ //            "Лицензия на ПО: ERP система",
+ //            "Продвижение и продажа товара через сайт",
+ //            "Чистая прибыль",
+ //            "Рентабельность по чистой прибыли, %"
+ //        ];
+         foreach (array_keys($indMap) as $code) {
+             $deviationFunc($code);
+         }
+         return $motivationDataTableSort;
+     }
  }
index b86942472cfdf584963b06ffac404f3551c97429,82dbbf5545c295bf95c9cf56e1b6086665b32e42..609caf8bad26fc1e9b22db705d265f357e780f28
@@@ -133,15 -144,10 +144,14 @@@ $this->registerJsFile('/js/motivation/i
                              'header' => 'План',
                          ],
                          [
--                            'attribute' => 'adjustment',
++                            'attribute' => 'correction',
                              'value' => function ($model) {
 -                                return $model['adjustment'] ?? '';
 +                                if ($model["adjustment"] !== null && $model["adjustment"] !== '') {
 +                                    return Yii::$app->formatter->asDecimal($model["adjustment"], 2);
 +                                } else {
 +                                    return " ";
 +                                }
                              },
                              'header' => 'Корректировка',
                          ],
                          [