From: Alexander Smirnov Date: Fri, 16 Aug 2024 13:40:52 +0000 (+0300) Subject: Merge branch 'develop' into feature_smirnov_erp-140_fact_motivation X-Git-Tag: 1.4~5^2~24 X-Git-Url: https://gitweb.erp-flowers.ru/?a=commitdiff_plain;h=11aec3845952f4d6aeeede54a5a81118cea61ab1;p=erp24_rep%2Fyii-erp24%2F.git Merge branch 'develop' into feature_smirnov_erp-140_fact_motivation # Conflicts: # erp24/controllers/MotivationController.php # erp24/services/MotivationService.php --- 11aec3845952f4d6aeeede54a5a81118cea61ab1 diff --cc erp24/controllers/MotivationController.php index c6cfd50e,e5c2b34c..7135447e --- a/erp24/controllers/MotivationController.php +++ b/erp24/controllers/MotivationController.php @@@ -16,7 -17,10 +17,11 @@@ class MotivationController extends Cont 'create-value' => \yii_app\actions\motivation\CreateValueAction::class, 'update-value' => \yii_app\actions\motivation\UpdateValueAction::class, 'delete-value' => \yii_app\actions\motivation\DeleteValueAction::class, + 'get-salary' => \yii_app\actions\motivation\GetSalaryAction::class, + 'sum-salary' => \yii_app\actions\motivation\SumSalaryAction::class, + 'mounth-salary' => \yii_app\actions\motivation\SumPreviousMonthSalaryAction::class, + 'sum-salary-by-month' => \yii_app\actions\motivation\SumSalaryByMonthAction::class, + 'test-fact' => \yii_app\actions\motivation\TestFactAction::class, ]; } diff --cc erp24/services/MotivationService.php index bb4e349d,d2eecf56..a379c5f3 --- a/erp24/services/MotivationService.php +++ b/erp24/services/MotivationService.php @@@ -20,8 -17,15 +18,10 @@@ use yii_app\records\Products1c use yii_app\records\ProductsClass; use yii_app\records\Sales; use yii_app\records\SalesProducts; + use yii_app\records\TimetableFactModel; + use yii_app\records\Timetable; - - -use yii_app\records\EmployeePayment; - - class MotivationService { @@@ -831,379 -948,63 +944,453 @@@ return $totalSalary + $vacationSum; } + + /** + * @param $currentDate + * @return array + */ + public static function getEmployeePayments($currentDate): array + { + // Запрос для получения всех записей, но только с учетом последней даты для каждого admin_id + $employeePayments = EmployeePayment::find() + ->where(['<=', 'date', $currentDate]) + ->orderBy(['admin_id' => SORT_ASC, 'date' => SORT_DESC]) + ->all(); + + // Преобразование результатов в массив admin_id => daily_payment + $dailyPayments = []; + foreach ($employeePayments as $payment) { + if (!isset($dailyPayments[$payment->admin_id])) { + $dailyPayments[$payment->admin_id] = $payment->daily_payment; + } + } + return $dailyPayments; + } + + /** + * Возвращает массив, представляющий недели месяца (с указаниме начала и конца недели) для указанного года и месяца. + * + * @param int|string $year Год в виде числа или строки (например, `2024` или `'2024'`). + * @param int|string $month Месяц в виде числа или строки (например, `2` или `'02'`). + * + * @return array Массив недель месяца, где каждая неделя представлена ассоциативным массивом с ключами 'start' и 'end'. + * Пример возвращаемого массива: + * [ + * ['start' => 1, 'end' => 7], + * ['start' => 8, 'end' => 14], + * ['start' => 15, 'end' => 21], + * ['start' => 22, 'end' => 28], + * ['start' => 29, 'end' => 30] // если месяц имеет больше 28 дней + * ] + */ + public static function getWeeksOfMonthArray($year, $month): array + { + // Массив недель, изначально включающий первые четыре недели + $weeks = [ + ['start' => 1, 'end' => 7], + ['start' => 8, 'end' => 14], + ['start' => 15, 'end' => 21], + ['start' => 22, 'end' => 28], + ]; + + // Определяем последний день месяца + $lastDayOfMonth = date('t', strtotime("$year-$month-01")); + + // Если в месяце больше 28 дней, добавляем пятую неделю + if ($lastDayOfMonth > 28) { + $weeks[] = ['start' => 29, 'end' => $lastDayOfMonth]; + } + + 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, + 6, 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, + 6, 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); + self::saveOrUpdateMotivationValue($motivation->id, + 6, 27, "float", $plan); + } + } + + 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); + self::saveOrUpdateMotivationValue($motivation->id, + 6, 28, "float", $plan); + } + } + + 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); + self::saveOrUpdateMotivationValue($motivation->id, + 6, 29, "float", $tariff * ($timetableFactModels[$motivation->store_id]['cnt'] ?? 0)); + } + } + + 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); + self::saveOrUpdateMotivationValue($motivation->id, + 6, 31, "float", $plan); + } + } + + 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); + self::saveOrUpdateMotivationValue($motivation->id, + 6, 32, "float", $plan); + } + } + + 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, + 6, 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, 6, $index, "float", 0); + } + } + } }