From: Alexander Smirnov Date: Thu, 29 Aug 2024 12:38:23 +0000 (+0300) Subject: Merge branch 'develop' into feature_smirnov_erp-140_fact_motivation X-Git-Tag: 1.4~5^2~17 X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=e7fb32373ae8123b7b9299f21a1db3689f78f54f;p=erp24_rep%2Fyii-erp24%2F.git Merge branch 'develop' into feature_smirnov_erp-140_fact_motivation # Conflicts: # erp24/services/MotivationService.php # erp24/views/motivation/index.php --- e7fb32373ae8123b7b9299f21a1db3689f78f54f diff --cc erp24/services/MotivationService.php index 65f870e7,dad9f984..f8d543da --- a/erp24/services/MotivationService.php +++ b/erp24/services/MotivationService.php @@@ -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 = [ @@@ -1004,398 -1106,243 +1102,638 @@@ 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; + } } diff --cc erp24/views/motivation/index.php index b8694247,82dbbf55..609caf8b --- a/erp24/views/motivation/index.php +++ b/erp24/views/motivation/index.php @@@ -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' => 'Корректировка', ], [