]> gitweb.erp-flowers.ru Git - erp24_rep/yii-erp24/.git/commitdiff
set actual code from erp
authorAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Fri, 15 Mar 2024 09:17:43 +0000 (12:17 +0300)
committerAleksey Filippov <Aleksey.Filippov@erp-flowers.ru>
Fri, 15 Mar 2024 09:17:43 +0000 (12:17 +0300)
284 files changed:
erp24/actions/cabinet/IndexClusterAction.php
erp24/actions/cabinet/PersonClusterAction.php
erp24/actions/dashboard/SalesAction.php
erp24/actions/grade/AdminUpdateAction.php
erp24/actions/infoTable/CabinetAction.php [new file with mode: 0644]
erp24/actions/payroll/IndexAction.php
erp24/actions/payroll/ListAdminsAction.php
erp24/actions/payroll/MakeAction.php
erp24/actions/payroll/StoreAction.php
erp24/actions/timetable/EditPlanAction.php
erp24/api2/controllers/BonusController.php
erp24/api3/config/bootstrap.php
erp24/api3/core/behaviors/EventBehavior.php
erp24/api3/core/services/BonusService.php
erp24/api3/core/services/ClaimService.php
erp24/api3/core/services/IncomeService.php
erp24/api3/core/services/NotifiableService.php [new file with mode: 0644]
erp24/api3/core/services/ReportService.php [new file with mode: 0644]
erp24/api3/core/services/StoreService.php
erp24/api3/core/services/TimetableService.php
erp24/api3/core/traits/ServiceTrait.php
erp24/api3/helpers/Util.php
erp24/api3/modules/v1/controllers/AdminController.php
erp24/api3/modules/v1/controllers/BonusController.php
erp24/api3/modules/v1/controllers/EmployeeController.php
erp24/api3/modules/v1/controllers/NotifiableController.php [new file with mode: 0644]
erp24/api3/modules/v1/controllers/ReportController.php [new file with mode: 0644]
erp24/api3/modules/v1/controllers/StoreController.php
erp24/api3/modules/v1/controllers/claim/WorkerController.php
erp24/api3/modules/v1/controllers/timetable/FactController.php
erp24/api3/modules/v1/models/Store.php
erp24/api3/modules/v1/models/orders/OrdersAmo.php
erp24/api3/modules/v1/models/timetable/Timetable.php
erp24/api3/modules/v1/requests/bonus/BonusWriteOffInput.php [new file with mode: 0644]
erp24/api3/modules/v1/requests/claim/Worker.php
erp24/api3/modules/v1/requests/report/ReportInput.php [new file with mode: 0644]
erp24/api3/modules/v1/requests/timetable/Fact.php
erp24/controllers/ChartForManagementController.php [new file with mode: 0644]
erp24/controllers/CityStoreController.php
erp24/controllers/InfoTableController.php
erp24/controllers/MatrixErpPropertyController.php
erp24/controllers/PagesController.php
erp24/controllers/ShipmentController.php [changed mode: 0644->0755]
erp24/controllers/SiteController.php
erp24/forms/timetable/TabelSearchForm.php
erp24/helpers/ClientHelper.php
erp24/helpers/DataHelper.php
erp24/helpers/File.php
erp24/helpers/HtmlHelper.php
erp24/helpers/SalaryHelper.php
erp24/records/AdminChats.php [changed mode: 0755->0644]
erp24/records/AdminCheckin.php
erp24/records/AdminDesktop.php
erp24/records/AdminDevice.php
erp24/records/AdminDynamic.php [changed mode: 0755->0644]
erp24/records/AdminDynamicCategoryDict.php [changed mode: 0755->0644]
erp24/records/AdminGradeHistory.php [changed mode: 0755->0644]
erp24/records/AdminGroup.php
erp24/records/AdminGroupCompanyFunctionVisibility.php [changed mode: 0755->0644]
erp24/records/AdminGroupRbacConfig.php [changed mode: 0755->0644]
erp24/records/AdminPayrollDays.php [changed mode: 0755->0644]
erp24/records/AdminPayrollDaysSearch.php [changed mode: 0755->0644]
erp24/records/AdminPayrollHistory.php [new file with mode: 0644]
erp24/records/AdminPayrollMonthInfo.php [changed mode: 0755->0644]
erp24/records/AdminPayrollStat.php [changed mode: 0755->0644]
erp24/records/AdminPersonBonuses.php
erp24/records/AdminStores.php [changed mode: 0755->0644]
erp24/records/ApiCron.php [changed mode: 0755->0644]
erp24/records/ApiCronTest.php [changed mode: 0755->0644]
erp24/records/ApiCronTestSearch.php [changed mode: 0755->0644]
erp24/records/ApiErrorLog.php [changed mode: 0755->0644]
erp24/records/ApiErrorLogSearch.php [changed mode: 0755->0644]
erp24/records/ApiLogs.php [changed mode: 0755->0644]
erp24/records/ApiLogsSearch.php [changed mode: 0755->0644]
erp24/records/Assemblies.php [changed mode: 0755->0644]
erp24/records/Balances.php [changed mode: 0755->0644]
erp24/records/BalancesSearch.php [changed mode: 0755->0644]
erp24/records/CalendarAdminLink.php [changed mode: 0755->0644]
erp24/records/Cashes.php [changed mode: 0755->0644]
erp24/records/ChartDataSearch.php [changed mode: 0755->0644]
erp24/records/CheckConduct.php [changed mode: 0755->0644]
erp24/records/CheckConductItem.php [changed mode: 0755->0644]
erp24/records/CheckCriteria.php [changed mode: 0755->0644]
erp24/records/CheckCriteriaItem.php [changed mode: 0755->0644]
erp24/records/CheckGroup.php [changed mode: 0755->0644]
erp24/records/CheckStatus.php [changed mode: 0755->0644]
erp24/records/CheckType.php [changed mode: 0755->0644]
erp24/records/City.php [changed mode: 0755->0644]
erp24/records/CityStoreSearch.php [changed mode: 0755->0644]
erp24/records/Cluster.php [changed mode: 0755->0644]
erp24/records/ClusterCalendar.php [changed mode: 0755->0644]
erp24/records/ClusterCalendarCategoryDict.php [changed mode: 0755->0644]
erp24/records/ClusterCalendarCategoryDictSearch.php [changed mode: 0755->0644]
erp24/records/ClusterSearch.php [changed mode: 0755->0644]
erp24/records/Comment.php [changed mode: 0755->0644]
erp24/records/Companies.php [changed mode: 0755->0644]
erp24/records/Company.php [changed mode: 0755->0644]
erp24/records/CompanyFunctions.php [changed mode: 0755->0644]
erp24/records/CompanySearch.php [changed mode: 0755->0644]
erp24/records/CompanyStores.php [changed mode: 0755->0644]
erp24/records/Contest001.php [changed mode: 0755->0644]
erp24/records/CreateChecks.php [changed mode: 0755->0644]
erp24/records/CreateChecks2.php [changed mode: 0755->0644]
erp24/records/CreateChecksBags.php [changed mode: 0755->0644]
erp24/records/CrmMenu.php
erp24/records/CrmMenuPermission.php [changed mode: 0755->0644]
erp24/records/CrmMenuPermissionSearch.php [changed mode: 0755->0644]
erp24/records/EmployeeOnShift.php [changed mode: 0755->0644]
erp24/records/ErrorInfoErp.php [changed mode: 0755->0644]
erp24/records/ErrorInfoErpSearch.php [changed mode: 0755->0644]
erp24/records/ErrorLog.php
erp24/records/ExportImport.php [changed mode: 0755->0644]
erp24/records/Firms.php [changed mode: 0755->0644]
erp24/records/FirmsGroupPrefix.php [changed mode: 0755->0644]
erp24/records/FunctionRegulations.php [changed mode: 0755->0644]
erp24/records/Grade.php [changed mode: 0755->0644]
erp24/records/GradeGroup.php [changed mode: 0755->0644]
erp24/records/GradePrice.php [changed mode: 0755->0644]
erp24/records/Holiday.php
erp24/records/ImageDocumentLink.php [changed mode: 0755->0644]
erp24/records/Images.php [changed mode: 0755->0644]
erp24/records/Incoming.php [changed mode: 0755->0644]
erp24/records/KikFeedbackCategory.php [changed mode: 0755->0644]
erp24/records/KikFeedbackRequest.php [changed mode: 0755->0644]
erp24/records/KikFeedbackSource.php [changed mode: 0755->0644]
erp24/records/KikFeedbackSubcategory.php [changed mode: 0755->0644]
erp24/records/KikFeedbackVerdict.php [changed mode: 0755->0644]
erp24/records/LessonsGroup.php [changed mode: 0755->0644]
erp24/records/MatrixErp.php [changed mode: 0755->0644]
erp24/records/MatrixErpMedia.php [changed mode: 0755->0644]
erp24/records/MatrixErpProperty.php [changed mode: 0755->0644]
erp24/records/MatrixErpPropertySearch.php [changed mode: 0755->0644]
erp24/records/MatrixErpSearch.php [changed mode: 0755->0644]
erp24/records/Meeting.php [changed mode: 0755->0644]
erp24/records/MeetingLinkAdmin.php [changed mode: 0755->0644]
erp24/records/MeetingSearch.php [changed mode: 0755->0644]
erp24/records/MessagerUser.php [changed mode: 0755->0644]
erp24/records/MultipleModel.php [changed mode: 0755->0644]
erp24/records/NewsLetterDeliveryStatus.php [changed mode: 0755->0644]
erp24/records/NotifiableUser.php [new file with mode: 0644]
erp24/records/Notification.php [changed mode: 0755->0644]
erp24/records/NotificationStatus.php [changed mode: 0755->0644]
erp24/records/OrderStoreSort.php [changed mode: 0755->0644]
erp24/records/OrdersAmo.php [changed mode: 0755->0644]
erp24/records/OurCities.php [changed mode: 0755->0644]
erp24/records/PaymentTypes.php [changed mode: 0755->0644]
erp24/records/PhoneChangeHistory.php [changed mode: 0755->0644]
erp24/records/PlanStore.php [changed mode: 0755->0644]
erp24/records/PlanStoreGroupSearch.php [changed mode: 0755->0644]
erp24/records/PlanStoreLog.php [changed mode: 0755->0644]
erp24/records/PlanStoreSearch.php [changed mode: 0755->0644]
erp24/records/Prices.php [changed mode: 0755->0644]
erp24/records/PricesZakup.php [changed mode: 0755->0644]
erp24/records/Products1c.php [changed mode: 0755->0644]
erp24/records/Products1cOptions.php [changed mode: 0755->0644]
erp24/records/ProductsVarieties.php [changed mode: 0755->0644]
erp24/records/QualityRating.php [changed mode: 0755->0644]
erp24/records/QualityRatingLog.php [changed mode: 0755->0644]
erp24/records/ReferralStatus.php [changed mode: 0755->0644]
erp24/records/Report.php [changed mode: 0755->0644]
erp24/records/Reports.php [changed mode: 0755->0644]
erp24/records/ReportsFields.php [changed mode: 0755->0644]
erp24/records/ReportsGroups.php [changed mode: 0755->0644]
erp24/records/RnpAlias.php [changed mode: 0755->0644]
erp24/records/RnpData.php [changed mode: 0755->0644]
erp24/records/RnpIndex.php [changed mode: 0755->0644]
erp24/records/SalesGroupSearch.php [changed mode: 0755->0644]
erp24/records/SalesHistory.php [changed mode: 0755->0644]
erp24/records/SalesHistorySearch.php [changed mode: 0755->0644]
erp24/records/SalesItems.php [changed mode: 0755->0644]
erp24/records/SalesProductsHistory.php [changed mode: 0755->0644]
erp24/records/SalesProductsHistorySearch.php [changed mode: 0755->0644]
erp24/records/SalesProductsUpdate.php [changed mode: 0755->0644]
erp24/records/SalesUpdate.php [changed mode: 0755->0644]
erp24/records/SchedulerTaskLogSearch.php
erp24/records/ScriptLauncherLog.php [changed mode: 0755->0644]
erp24/records/Shift.php
erp24/records/StoreDynamic.php [changed mode: 0755->0644]
erp24/records/StoreOrderStatus.php [changed mode: 0755->0644]
erp24/records/StoreOrders.php [changed mode: 0755->0644]
erp24/records/StoreOrdersFields.php [changed mode: 0755->0644]
erp24/records/StoreOrdersFieldsData.php [changed mode: 0755->0644]
erp24/records/StoreOrdersFieldsProperty.php [changed mode: 0755->0644]
erp24/records/StorePlanogram.php [changed mode: 0755->0644]
erp24/records/Task.php [changed mode: 0755->0644]
erp24/records/TaskSearch.php [changed mode: 0755->0644]
erp24/records/TaskTemplates.php [changed mode: 0755->0644]
erp24/records/TeambonusSettings.php [changed mode: 0755->0644]
erp24/records/TechnicalRequestType.php [changed mode: 0755->0644]
erp24/records/TechnicalRequestTypeSearch.php [changed mode: 0755->0644]
erp24/records/Terminals.php [changed mode: 0755->0644]
erp24/records/TimeDiffValue.php [changed mode: 0755->0644]
erp24/records/Timetable.php
erp24/records/TimetableShift.php [changed mode: 0755->0644]
erp24/records/TimetableWorkbot.php [changed mode: 0755->0644]
erp24/records/UniversalCatalog.php [changed mode: 0755->0644]
erp24/records/UniversalCatalogItem.php [changed mode: 0755->0644]
erp24/records/UniversalCatalogItemSearch.php [changed mode: 0755->0644]
erp24/records/UniversalCatalogSearch.php [changed mode: 0755->0644]
erp24/records/UsersAuthCallLog.php [changed mode: 0755->0644]
erp24/records/UsersBonus.php [changed mode: 0755->0644]
erp24/records/UsersEvents.php [changed mode: 0755->0644]
erp24/records/UsersPhones.php [changed mode: 0755->0644]
erp24/records/UsersStopList.php [changed mode: 0755->0644]
erp24/records/UsersStopListSearch.php [changed mode: 0755->0644]
erp24/records/WriteOffsErp.php [changed mode: 0755->0644]
erp24/records/WriteOffsErpCauseDict.php [changed mode: 0755->0644]
erp24/records/WriteOffsErpCauseDictSearch.php [changed mode: 0755->0644]
erp24/records/WriteOffsErpSearch.php [changed mode: 0755->0644]
erp24/records/WriteOffsProductsErp.php [changed mode: 0755->0644]
erp24/records/detection.dat [changed mode: 0755->0644]
erp24/records/metrics/FotMetrics.php [new file with mode: 0644]
erp24/records/metrics/MatrixMetrics.php [new file with mode: 0644]
erp24/records/metrics/Metrics.php [new file with mode: 0755]
erp24/records/metrics/SalesMetrics.php [new file with mode: 0644]
erp24/records/metrics/UserBonusMetrics.php [new file with mode: 0644]
erp24/records/metrics/WriteOffsMetrics.php [new file with mode: 0644]
erp24/scripts/tasks/task_04_dashboard_sales.php
erp24/scripts/tasks/task_06_set_payroll_by_day.php
erp24/scripts/tasks/task_09_contest001_update.php
erp24/scripts/tasks/task_17_set_payroll_info_by_month.php
erp24/scripts/tasks/task_20_give_500_to_referral_program_participants.php
erp24/scripts/tasks/task_21_calculation_company_data_sales.php [new file with mode: 0644]
erp24/scripts/tasks/task_22_create_employee_for_1c_with_admins_with_empty_guid.php
erp24/scripts/tasks/task_23_calculation_company_data_users_bonus.php [new file with mode: 0644]
erp24/scripts/tasks/task_24_calculation_company_data_matrix_sales.php [new file with mode: 0644]
erp24/scripts/tasks/task_25_delivery_bonus_add_after_half_day.php
erp24/scripts/tasks/task_26_delivery_bonus_add_after_weak.php
erp24/scripts/tasks/task_27_set_payroll_history.php [new file with mode: 0755]
erp24/scripts/tasks/task_28_calculation_company_data_fot.php [new file with mode: 0644]
erp24/scripts/tasks/task_29_calculation_company_data_write_offs.php [new file with mode: 0644]
erp24/scripts/tasks/task_30_calculation_company_data_matrix_for_chart.php [new file with mode: 0644]
erp24/services/AdminPayrollMonthInfoService.php
erp24/services/BonusService.php
erp24/services/CabinetService.php
erp24/services/DashboardService.php
erp24/services/HolidayService.php [new file with mode: 0644]
erp24/services/SalesService.php
erp24/tests/_bootstrap.php [changed mode: 0644->0755]
erp24/tests/_data/.gitignore [new file with mode: 0755]
erp24/tests/_data/city.php [new file with mode: 0755]
erp24/tests/_output/.gitignore [changed mode: 0644->0755]
erp24/tests/_support/.gitignore [new file with mode: 0755]
erp24/tests/_support/FunctionalTester.php [changed mode: 0644->0755]
erp24/tests/_support/UnitTester.php [changed mode: 0644->0755]
erp24/tests/fixtures/CityFixture.php [new file with mode: 0755]
erp24/tests/functional.suite.yml [changed mode: 0644->0755]
erp24/tests/functional/CityCest.php [new file with mode: 0755]
erp24/tests/functional/_bootstrap.php [changed mode: 0644->0755]
erp24/tests/unit.suite.yml [changed mode: 0644->0755]
erp24/tests/unit/_bootstrap.php [changed mode: 0644->0755]
erp24/tests/unit/models/CityTest.php [new file with mode: 0755]
erp24/views/admin_person_bonuses/_form.php
erp24/views/admin_person_bonuses/_update_form.php
erp24/views/admin_person_bonuses/create.php
erp24/views/admin_person_bonuses/index.php
erp24/views/admin_person_bonuses/update.php
erp24/views/admin_person_bonuses/view.php
erp24/views/cabinet202310/_admin_salary_by_stores_table.php
erp24/views/cabinet202310/_already_pay_in_month.php [new file with mode: 0644]
erp24/views/cabinet202310/_cluster_personal_values.php
erp24/views/cabinet202310/_holiday_table_values.php [new file with mode: 0755]
erp24/views/cabinet202310/_personal_info.php
erp24/views/cabinet202310/_personal_values.php
erp24/views/cabinet202310/_table_salary_checks.php
erp24/views/cabinet202310/_table_team_payroll.php [new file with mode: 0755]
erp24/views/cabinet202310/administrator.php
erp24/views/cabinet202310/cluster.php
erp24/views/cabinet202310/florist.php
erp24/views/city_store/index.php
erp24/views/crud/employee-payment/_search.php
erp24/views/dashboard/sales.php
erp24/views/info_table/cabinet.php [new file with mode: 0644]
erp24/views/lesson/analytics.php
erp24/views/matrix_erp_property/_form.php
erp24/views/payroll/list-admins.php
erp24/views/scheduler_task_log/index.php
erp24/views/shipment/division-print-edit.php [new file with mode: 0644]
erp24/views/shipment/fields-data.php [new file with mode: 0644]
erp24/views/shipment/index.php [changed mode: 0644->0755]
erp24/views/shipment/set-division-priority.php [new file with mode: 0644]
erp24/views/timetable/plan.php
erp24/views/timetable/start_shift_step_three.php
erp24/views/timetable/tabel_edit.php

index 39b23751d8175bd3eea339f067a82740354b3c70..52c8f99b45f9a1ecec1f97ec76e9d517fb236719 100755 (executable)
@@ -116,9 +116,9 @@ class IndexClusterAction extends Action
             ->indexBy('id');
 
 
-        if (3 == date("n",strtotime($dateFrom)) || 3 == date("n",strtotime($dateTo))) {
-            $queryClusterAdmin->andWhere(['parent_admin_id' => 182]); // для исключения директора по доставке
-        }
+//        if (3 == date("n",strtotime($dateFrom)) || 3 == date("n",strtotime($dateTo))) {
+//            $queryClusterAdmin->andWhere(['parent_admin_id' => 182]); // для исключения директора по доставке
+//        }
 
         if (date("Y-m-d",strtotime($dateFrom))  < '2023-04-01' && date("Y-m-d",strtotime($dateTo)) < '2023-04-30') {
             $queryClusterAdmin->andWhere(['parent_admin_id' => 182]); // для исключения директора по доставке
@@ -226,6 +226,14 @@ class IndexClusterAction extends Action
 
         $param = array_merge($param, $paramAdditionsValue);
 
-        return $this->controller->render('/cabinet/cluster', $param);
+        $cabinetPrefix = '';
+
+        if ($dateFrom >= '2023-10-01') {
+            $cabinetPrefix = '202310';
+        }
+
+        $view = '/cabinet' . $cabinetPrefix . '/cluster';
+
+        return $this->controller->render($view, $param);
     }
 }
index b70e135a760f2b5a87932fdab00069a5ce66f884..1cbfdab6a749af5e6e1ce53c78402077f3378f8a 100755 (executable)
@@ -66,10 +66,10 @@ class PersonClusterAction extends Action
             ->indexBy('id');
 
 
-
-        if (3 == date("n",strtotime($dateFrom)) || 3 == date("n",strtotime($dateTo))) {
-            $queryClusterAdmin->andWhere(['parent_admin_id' => 182]); // для исключения директора по доставке
-        }
+//
+//        if (3 == date("n",strtotime($dateFrom)) || 3 == date("n",strtotime($dateTo))) {
+//            $queryClusterAdmin->andWhere(['parent_admin_id' => 182]); // для исключения директора по доставке
+//        }
 
 
             $clusterAdmin = $queryClusterAdmin->asArray()->one();
index 522db8b50bb9f1a5498511c9a74534a772c0b5ce..64f6e5461ad7147ada05ccb1b52feed3cd8578d4 100755 (executable)
@@ -125,11 +125,6 @@ class SalesAction extends Action
         $date2_smen_time=strtotime($date2)+86400;
         $date2_smen=date("Y-m-d",$date2_smen_time);
 
-        $sales_products = [];
-        if(!empty($check_id)) {
-            $sales_products = $salesService->getSalesProducts($check_id);
-        }
-
         $equal_days = ($date1==$date2);
 
         $arr_work = [
@@ -238,8 +233,6 @@ class SalesAction extends Action
         $saleServices = $salesService->getSalesServices($date1, $date2);
         $saleServicesIds = ArrayHelper::getColumn($saleServices, 'id');
 
-        $checkSellerDiscount = SalesProductsService::getCheckSellerDiscount($saleServicesIds);
-
         $params = [
             'shift' => $shift,
             'date1' => $date1,
@@ -252,7 +245,6 @@ class SalesAction extends Action
             'number' => $number,
             'city_stores' => $city_stores,
             'store_traffik' => $store_traffik,
-            'sales_products' => $sales_products,
             'equal_days' => $equal_days,
             'arr_work' => $arr_work,
             'date_timetable' => $date_timetable,
@@ -272,7 +264,6 @@ class SalesAction extends Action
             'productsArrayServices' => $productsArrayServices,
             'servises' => $servises,
             'saleServices' => $saleServices,
-            'checkSellerDiscount' => $checkSellerDiscount,
             'daysSearchForm' => $daysSearchForm,
         ];
 
index b74fab67dfec2495bb954a6ef76bd30d0060bb86..6fab23679e6c87f68d765f1fd3588fc8b29687c9 100644 (file)
@@ -24,11 +24,6 @@ class AdminUpdateAction extends Action
         if (Yii::$app->user->can("updateAdminSettings", ['id' => $model->id])) {
             if (Yii::$app->request->isPost) {
                 $attributes = Yii::$app->request->post()['Admin'];
-                $mobile = $attributes['mobile'];
-                if (mb_strlen($mobile) > 2 && $mobile[0] == 8 && $mobile[1] = 9) {
-                    $mobile[0] = 7;
-                    $attributes['mobile'] = $mobile;
-                }
                 foreach (['parent_admin_id', 'org_id'] as $fieldName) {
                     if (empty($attributes[$fieldName])) {
                         $attributes[$fieldName] = 0;
diff --git a/erp24/actions/infoTable/CabinetAction.php b/erp24/actions/infoTable/CabinetAction.php
new file mode 100644 (file)
index 0000000..e8a1753
--- /dev/null
@@ -0,0 +1,13 @@
+<?php
+
+namespace yii_app\actions\infoTable;
+
+use yii\base\Action;
+
+class CabinetAction extends Action
+{
+    public function run() {
+        return $this->controller->render('/info_table/cabinet.php', []);
+    }
+
+}
\ No newline at end of file
index f2f0bfb33f2d79c9534d28cb6a3a19da6624cb76..659f8789c9304d9a0c7f59d7b93c7795940715b2 100755 (executable)
@@ -125,6 +125,7 @@ class IndexAction extends Action
                 'allTotalPayroll', // ЗП
                 'personPrepaidExpense',
                 'personCounting',
+                'partTimeWagesSumAdminAllStore',
                 'personRetention',
                 'toPayoff',
             ];
index 556145e2536954b10a3e71ecf612ed8d56bec76e..52ddee70a6e3331fe9eca489a2b90faa8855706b 100755 (executable)
@@ -11,6 +11,7 @@ use yii_app\forms\timetable\TabelSearchForm;
 use yii_app\helpers\HtmlHelper;
 use yii_app\records\AdminGroup;
 use yii_app\records\AdminPayroll;
+use yii_app\records\AdminPayrollHistory;
 use yii_app\records\AdminPayrollValues;
 use yii_app\records\AdminPayrollValuesDict;
 use yii_app\records\CityStore;
@@ -134,7 +135,7 @@ class ListAdminsAction extends Action
 
         $aliasSumFields = [
             'oklad', // Оклад
-            'deltaWagesAdmin',
+//            'deltaWagesAdmin',
             'worksDayByTableFromSelectDay', // Число смен в графике
             'adminSumGameCountShiftTotal', // Число смен геймификации
             'personVacationDay',
@@ -148,9 +149,11 @@ class ListAdminsAction extends Action
             'bonusMakeMatrix',
             'teamBonusValue',
             'userQualityPremium',
-            'adminSumGameBonusConversionToMoney',
+//            'adminSumGameBonusConversionToMoney',
             'personBonuses', // Персональная Премия
             'allTotalPayroll', // ЗП
+            'adminPayrollCurrentLk', // Значение из личного кабинета
+            'adminPayrollDelta', // Дельта значения из личного кабинета и текущего в ведомости
             'personPrepaidExpense',
             'personCounting',
             'personRetention',
@@ -165,10 +168,31 @@ class ListAdminsAction extends Action
             ->asArray()
             ->all();
 
+        $lastPacketNum = AdminPayrollHistory::find()
+            ->select(['packet_num'])
+            ->andWhere(['year' => $yearSelect])
+            ->andWhere(['month' => $monthWithZeroSelect])
+            ->orderBy(['packet_num' => SORT_DESC])
+            ->distinct(true)
+            ->scalar();
+
+        $lastPacketDate = date('d.m.Y H:i:s', $lastPacketNum);
+
+        $adminPayrollCurrentLk = AdminPayrollHistory::find()
+            ->select(['admin_id', 'admin_payroll_history.value_number AS value'])
+            ->andWhere(['year' => $yearSelect])
+            ->andWhere(['group_number' => AdminPayrollHistory::GROUP_VALUE_ALL_TOTAL_PAYROLL])
+            ->andWhere(['month' => $monthWithZeroSelect])
+            ->andWhere(['packet_num' => $lastPacketNum])
+            ->indexBy('admin_id')
+            ->asArray()
+            ->all();
+
         $sumColumnByAlias = [];
 
         foreach ($adminPayroll as $key => $rowAdmins) {
             $payrollIds = $rowAdmins['id'];
+            $adminIdRow = $rowAdmins['admin_id'];
             foreach ($aliasSumFields as $keyAlias => $alias) {
                 if (array_key_exists($alias, $adminPayrollValuesDict)) {
                     $keyRow = $alias.'.id';
@@ -184,6 +208,43 @@ class ListAdminsAction extends Action
                     if (!empty($sumRow)) {
                         $sumColumnByAlias[$keyAlias] += $sumRow;
                     }
+                } else {
+                    if ($dateFrom >= '2023-12-01') {
+                        $sumRow = 0;
+                        if ('adminPayrollCurrentLk' == $alias) {
+                            $payrollStoreColumn[$alias] = 'Значение ЗП в ЛК <br>( на ' . $lastPacketDate . ')';
+
+                            if (array_key_exists($adminIdRow, $adminPayrollCurrentLk)) {
+                                $keySumRow = $adminIdRow . '.value';
+                                $sumRow = (float) ArrayHelper::getValue($adminPayrollCurrentLk, $keySumRow);
+                            }
+                            $adminPayroll[$key]['column'][$alias] = $sumRow;
+
+                        }
+                        if ('adminPayrollDelta' == $alias) {
+                            $payrollStoreColumn[$alias] = 'Разница ЗП между ведомостью и ЛК';
+
+                            $sumHistoryRow = 0;
+                            if (!empty($adminPayroll[$key]['column']['adminPayrollCurrentLk'])) {
+                                $sumHistoryRow = $adminPayroll[$key]['column']['adminPayrollCurrentLk'];
+                            }
+                            $sumPayrollRow = 0;
+                            $keyAliasNameRow = 'allTotalPayroll.name';
+                            $aliasNameRow = ArrayHelper::getValue($adminPayrollValuesDict, $keyAliasNameRow);
+                            if (!empty($adminPayroll[$key]['column'][$aliasNameRow])) {
+                                $sumPayrollRow = $adminPayroll[$key]['column'][$aliasNameRow];
+                            }
+                            $sumRow = $sumPayrollRow - $sumHistoryRow;
+                            $adminPayroll[$key]['column']['adminPayrollDelta'] = $sumRow;
+                            //allTotalPayroll
+                        }
+                        if (!array_key_exists($keyAlias, $sumColumnByAlias)) {
+                            $sumColumnByAlias[$keyAlias] = 0;
+                        }
+                        if (!empty($sumRow)) {
+                            $sumColumnByAlias[$keyAlias] += $sumRow;
+                        }
+                    }
                 }
             }
         }
@@ -212,6 +273,7 @@ class ListAdminsAction extends Action
             'yearMonthSearchForm' => $yearMonthSearchForm,
             'sumColumnByAlias' => $sumColumnByAlias,
             'monthNameSelect' => $monthNameSelect,
+            'lastPacketDate' => $lastPacketDate,
         ]);
     }
 }
\ No newline at end of file
index 7da9d241bde5874b04569735e8c9b22d7773a903..a0b494fa1f6e87a780b0235e5ce7de5063d088bc 100755 (executable)
@@ -194,6 +194,9 @@ class MakeAction extends Action
                 'saveValuesOk' => 'saveValuesOk',
                 'Командный бонус' => 'teamBonusValue',
                 'Премия за качество' => 'userQualityPremium',
+                'Командный бонус детально' => 'teamBonusDetail',
+                'Оклады за подработку' => 'partTimeWagesSumAdminAllStore',
+                'Число смен подработок' => 'partTimeWagesCountAdminAllStore',
             ];
 
             $adminPayrollValuesDict = AdminPayrollValuesDict::find()
@@ -301,15 +304,7 @@ class MakeAction extends Action
                 ]);
             }
 
-            $groupIds = [
-                30,
-                35,
-                40,
-                45, // подработчики
-                50, // Администраторы
-                72, //
-                -1
-            ];
+            $groupIds = Admin::ADMIN_PAYROLL_MAKE_GROUP_IDS;
 
             // пропускать недавно обновлённые, за последние 20 минут
             $dateCheckReset = date("Y-m-d H:i:s", time() - (60 * 60));
index 463e02f552a5aca6e405b617e0fb79ae936e9781..75f07141fd21dc473022adee048f869ba99abd24 100755 (executable)
@@ -150,6 +150,7 @@ class StoreAction extends Action
             $aliasSumFields = [
                 'oklad', // Оклад
                 'worksDayByTableFromSelectDay', // Число смен в графике
+                'partTimeWagesCountAdminAllStore',
                 'personVacationDay',
                 'personVacationPay',
                 'userSalaryServicesPremium',
@@ -165,6 +166,7 @@ class StoreAction extends Action
                 'allTotalPayroll', // ЗП
                 'personPrepaidExpense',
                 'personCounting',
+                'partTimeWagesSumAdminAllStore',
                 'personRetention',
                 'toPayoff',
             ];
index ccc4d811b9898d6384e02201690f0d0c374c547a..5db84ca66d18be49511942105d1a559012cecaa3 100755 (executable)
@@ -3,9 +3,11 @@ declare(strict_types = 1);
 
 namespace yii_app\actions\timetable;
 
+use Yii;
 use yii\base\Action;
 use yii\web\Response;
 use yii_app\records\Admin;
+use yii_app\records\Timetable;
 use yii_app\records\TimetableFact;
 use yii_app\records\TimetablePlan;
 
@@ -36,7 +38,6 @@ class EditPlanAction extends Action
             'store_id' => $this->controller->request->get('storeId'),
         ];
         $slot = TimetablePlan::find()->andWhere($row)->one();
-        $fact = TimetableFact::find()->andWhere(['plan_id' => $slot->id])->one();
         if (!$slot) {
             $slot = new TimetablePlan($row);
             /** @var Admin $admin */
@@ -57,6 +58,7 @@ class EditPlanAction extends Action
             $slot->time_start = $slot->shift ? $slot->shift->start_time : null;
             $slot->time_end = $slot->shift ? $slot->shift->end_time : null;
         }
+        $fact = TimetableFact::find()->andWhere(['plan_id' => $slot->id])->one();
         return $this->controller->renderPartial('/timetable/tabel_edit.php', [
             'slot' => $slot,
             'fact' => $fact,
@@ -110,7 +112,14 @@ class EditPlanAction extends Action
         $slot->admin_group_id = $slot->validate(['admin_id']) ? $slot->admin->group_id : null;
 
         if ($slot->validate(null, false)) {
-            $slot->save(false);
+            $session = Yii::$app->session;
+            $groupId = (int) $session->get('group_id');
+
+            $numDay = Timetable::getCountDaysAllowEditShift($groupId);
+
+            if (Timetable::getAllowEditShift($slot->date, $numDay)) {
+                $slot->save(false);
+            }
         }
         return $this->makeResponse($slot);
     }
index b6e3fa15b3f49557fe67ce4fe144611156438df5..9e37cbccdbca3bd5d1823a1a7405b54ba0658dee 100644 (file)
@@ -9,6 +9,7 @@ use yii_app\helpers\ClientHelper;
 use yii_app\records\Contest001;
 use yii_app\records\ExportImportTable;
 use yii_app\records\MessagerUser;
+use yii_app\records\NotifiableUser;
 use yii_app\records\Products1c;
 use yii_app\records\Sales;
 use yii_app\records\Timetable;
@@ -33,6 +34,8 @@ class BonusController extends BaseController
     private static $SECOND_SALE_PROCENT = 0.15;
     private static $MAX_PROCENT = 0.2;
     private static $CREDIT_PROCENT = 0.1;
+    private static $CREDIT_HIGH_PROCENT = 0.3;
+    private static $CREDIT_HIGH_PROCENT_PART20 = 0.2;
 
     public function actionGetBonuses()
     {
@@ -96,10 +99,16 @@ class BonusController extends BaseController
 
         $percent = ($result['phone'] == "79049031399") ? 0.9 : $max_procent;
 
-        $will_be_credited_bonuses = self::$CREDIT_PROCENT * $baza;
-        if ($result['phone'] == "79049031399") {
-            $will_be_credited_bonuses = $percent * $check_amount;
+        $userFound = Users::find()->where(['phone' => $result['phone']])->one();
+        /** @var $userFound Users */
+        $salesCount = 0;
+        if ($userFound && $userFound->telegram_created_at) {
+            $salesCount = intval(Sales::find()->where(['phone' => $result['phone'], 'operation' => Sales::OPERATION_SALE])
+                ->andWhere(['>=', 'date', $userFound->telegram_created_at])->count());
         }
+        $credit_procent = $userFound && $userFound->source > 0 && $salesCount == 0 ? self::$CREDIT_HIGH_PROCENT : self::$CREDIT_PROCENT;
+        $will_be_credited_bonuses = $credit_procent * $baza;
+
         $will_be_credited_bonuses = round($will_be_credited_bonuses);
         $mess["will_be_credited_bonuses"] = $will_be_credited_bonuses;
 
@@ -599,7 +608,13 @@ class BonusController extends BaseController
         // получаем внутренний ID продаца - сотрудника из таблицы admin
         $store_id = ClientHelper::getExportId($store_id_1c, "city_store", 1);
 
-        if ($write_off_bonuses) {
+        $writeOffAlready = false;
+        if (!empty($lid_id)) {
+            $writeOffAlready = UsersBonus::find()->where(['lid_id' => $lid_id, 'phone' => $phone, 'tip_sale' => 'sale', 'tip' => 'minus'])->one() != null;
+        }
+
+        $user_balans_new = $user_balans;
+        if ($write_off_bonuses && !$writeOffAlready) {
             $user_balans_new = $user_balans - $write_off_bonuses;
             $name_b = "Спиcание бонусов по чеку $check_name";
             $usersBonus = new UsersBonus;
@@ -642,8 +657,17 @@ class BonusController extends BaseController
                 FILE_APPEND | LOCK_EX);
         }
         //начисляем кэшбек клиенту 10% от покупки - с базы за вычитом бонусов которые он списывает
-        $back = round($baza_back * self::$CREDIT_PROCENT);
-        $nm = "Возврат с покупки 10% $check_name сумма чека $check_amount";
+        $userFound = Users::find()->where(['phone' => $result['phone']])->one();
+        /** @var $userFound Users */
+        $salesCount = 0;
+        if ($userFound && $userFound->telegram_created_at) {
+            $salesCount = intval(Sales::find()->where(['phone' => $result['phone'], 'operation' => Sales::OPERATION_SALE])
+                ->andWhere(['>=', 'date', $userFound->telegram_created_at])->count());
+        }
+        $credit_procent_index = $userFound && $userFound->source > 0 && $salesCount == 0 ? 1 : 0;
+
+        $back1 = $back = round($baza_back * self::$CREDIT_PROCENT);
+        $nm = "Возврат с покупки " . (100 * self::$CREDIT_PROCENT) . "% $check_name сумма чека $check_amount";
         $userBonus2 = UsersBonus::find()->where(['phone' => $phone])->andWhere(['check_id' => $check_id])->andWhere(['site_id' => $site_id])
             ->andWhere(['store_id' => $store_id])->andWhere(['tip' => 'plus'])->andWhere(['bonus' => $back])->andWhere(['name' => $nm])->one();
         if (!$userBonus2) {
@@ -667,10 +691,10 @@ class BonusController extends BaseController
             $userBonus2->price = $summa_chek;
             $userBonus2->store_id_1c = $store_id_1c;
             $userBonus2->seller_id_1c = $seller_id;
-            $userBonus2->user_id = $user_id;                // Поле не заполнялось в старом апи, но без него бд выдаёт ошибку при сохранении
-            $userBonus2->lid_id = $lid_id;                  // Поле не заполнялось в старом апи, но без него бд выдаёт ошибку при сохранении
-            $userBonus2->price_skidka = 0;                  // Поле не заполнялось в старом апи, но без него бд выдаёт ошибку при сохранении
-            $userBonus2->date_dell = $userBonus2->date_end; // Поле не заполнялось в старом апи, но без него бд выдаёт ошибку при сохранении
+            $userBonus2->user_id = $user_id;
+            $userBonus2->lid_id = $lid_id;
+            $userBonus2->price_skidka = 0;
+            $userBonus2->date_dell = $userBonus2->date_end;
             $userBonus2->save();
             if ($userBonus2->getErrors()) {
 
@@ -681,6 +705,61 @@ class BonusController extends BaseController
             file_put_contents(self::$USERS_AUTH_CALL_LOG2,
                 "" . date("d.m.Y H:i:s", time()) . " PLUS bonus=" . $back . "\n",
                 FILE_APPEND | LOCK_EX);
+            if ($credit_procent_index) {
+                $back = round($baza_back * self::$CREDIT_HIGH_PROCENT_PART20);
+                $nm = "Возврат с покупки " . (100 * self::$CREDIT_HIGH_PROCENT_PART20) . "% $check_name сумма чека $check_amount";
+
+                $user_balans_new += $back;
+
+                $userBonus2 = new UsersBonus;
+                $userBonus2->tip = 'plus';
+                $userBonus2->tip_sale = 'sale';
+                $userBonus2->date = date('Y-m-d H:i:s');
+                $userBonus2->date_start = date('Y-m-d H:i:s', strtotime('+1 day', time()));
+                $userBonus2->date_end = date('Y-m-d H:i:s', strtotime('+3 month', time()));
+                $userBonus2->phone = $phone;
+                $userBonus2->name = $nm;
+                $userBonus2->check_id = $check_id;
+                $userBonus2->store_id = $store_id;
+                $userBonus2->bonus = $back;
+                $userBonus2->ip = $ip;
+                $userBonus2->site_id = $site_id;
+                $userBonus2->referal_id = 0;
+                $userBonus2->admin_id = $admin_id;
+                $userBonus2->price = $summa_chek;
+                $userBonus2->store_id_1c = $store_id_1c;
+                $userBonus2->seller_id_1c = $seller_id;
+                $userBonus2->user_id = $user_id;
+                $userBonus2->lid_id = $lid_id;
+                $userBonus2->price_skidka = 0;
+                $userBonus2->date_dell = $userBonus2->date_end;
+                $userBonus2->save();
+                if ($userBonus2->getErrors()) {
+
+                    LogService::apiErrorLog(json_encode(["error_id" => 5.2, "error" => $userBonus2->getErrors()], JSON_UNESCAPED_UNICODE));
+
+                    return $this->asJson(["error_id" => 5.2, "error" => $userBonus2->getErrors()]);
+                }
+                if ($userFound->telegram_created_at == null) {
+                    $userFound->telegram_created_at = date("Y-m-d H:i:s");
+                    $userFound->save();
+                    if ($userFound->getErrors()) {
+
+                        LogService::apiErrorLog(json_encode(["error_id" => 5.3, "error" => $userFound->getErrors()], JSON_UNESCAPED_UNICODE));
+
+                        return $this->asJson(["error_id" => 5.3, "error" => $userFound->getErrors()]);
+                    }
+                }
+
+                $notifiableUser = new NotifiableUser;
+                $notifiableUser->phone = $phone;
+                $notifiableUser->type = "first_given_bonus";
+                $notifiableUser->data = "" . ($back1 + $back);
+                $notifiableUser->save();
+                if ($notifiableUser->getErrors()) {
+                    return $this->asJson(["error_id" => 5.4, "error" => $notifiableUser->getErrors()]);
+                }
+            }
         }
 
 //        /////// Добавляем бонусов рефералу
@@ -1167,7 +1246,7 @@ class BonusController extends BaseController
         }
 
         //
-        if (!in_array($result['tip_sale'], ['podarok', 'senat', 'nino802'])) {
+        if (!in_array($result['tip_sale'], ['podarok', 'senat', 'nino802', 'sale', '14feb', '23feb', '8mar'])) {
             return $this->asJson(["error_id" => 1.1, "error" => "tip_sale не разрешён (podarok, senat, nino802)"]);
         }
 
index 13643ff057e6a56f1cb2fda1d83482200ae1b7ad..238f3a01305b9e68a5d0caca24baf7dbdcc32a42 100644 (file)
@@ -3,4 +3,4 @@
 $yiiApp = dirname(__DIR__, 3);
 
 Yii::setAlias('@yii_app', $yiiApp);
-Yii::setAlias('@upload-checkin', dirname(__DIR__, 3) . "/uploads/checkin");
\ No newline at end of file
+Yii::setAlias('@upload-checkin', dirname(__DIR__, 3) . "/data/admin");
\ No newline at end of file
index e191a528a3286733d2df03eac2b67d9ee7782b72..c0eb6464731b569d6ee37cf1209c79fc7364bb38 100644 (file)
@@ -59,10 +59,10 @@ class EventBehavior extends Behavior
                         $error['code'] = $response->data['code'];
                     }
                 } elseif($exception instanceof HttpException) {
-                    $error['type'] = $response->data['name'] ? strtolower(str_replace($response->data['name'], " ", "_")) : "invalid_request";
+                    $error['type'] = $response->data['name'] ? strtolower(str_replace($response->data['name'], " ", "_")) : "invalid_request_type_1";
                     $error['message'] = $exception->getMessage();
                 } elseif($exception instanceof InvalidArgumentException) {
-                    $error['type'] = "invalid_request";
+                    $error['type'] = "invalid_request_type_2";
                     $error['message'] = $exception->getMessage();
                 }
 
index 461bea44a7a75166a88eab64ed2557ffdd51a28a..e37e5fabf72855a5965a222997f0d0992d28c572 100644 (file)
@@ -672,4 +672,49 @@ class BonusService
 
         return true;
     }
+
+    /**
+     * @throws \yii\base\Exception
+     * @throws Exception
+     */
+    public function bonusWriteOff($data) {
+        $phone = $data->phone;
+        $price = $data->price;
+        $bonus = $data->bonus;
+        $lid_id = $data->lid_id;
+
+        $stop = UsersStopList::find()->select(['phone'])->where(['phone' => $data->phone])->one();
+        if ($stop) {
+            throw new InvalidArgumentException("Номер телефона числится в стоп листе");
+        }
+
+        $found = UsersBonus::find()->where(['phone' => $phone])->andWhere(['>=', 'date_start', date('Y-m-d H:i:s', time() - 14 * 86400)])
+            ->andWhere(['tip_sale' => 'sale'])->andWhere(['tip' => 'minus'])->andWhere(['lid_id' => $lid_id])->andWhere(['bonus' => $bonus])->one();
+
+        if ($found) {
+            throw new InvalidArgumentException("Бонусы уже списаны");
+        }
+
+        $userBonus = new UsersBonus;
+        $userBonus->phone = $phone;
+        $userBonus->name = "Списание $bonus бонусов с заказа номер $lid_id на общую сумму $price";
+        $userBonus->date = date('Y-m-d H:i:s');
+        $userBonus->site_id = 1;
+        $userBonus->setka_id = 1;
+        $userBonus->tip = 'minus';
+        $userBonus->tip_sale = 'sale';
+        $userBonus->bonus = $bonus;
+        $userBonus->price = $price;
+        $userBonus->lid_id = $lid_id;
+        $userBonus->date_start = $data->date_start ?? $userBonus->date;
+        $userBonus->date_end = $data->date_end ?? date("Y-m-d H:i:s", strtotime("+" . self::$YEAR_PERIOD . ' days', strtotime($userBonus->date)));
+        $userBonus->save();
+
+        if ($userBonus->getErrors()) {
+            LogService::apiErrorLog(json_encode(["error_id" => 2, "error" => $userBonus->getErrors()], JSON_UNESCAPED_UNICODE));
+            throw new InvalidArgumentException(array_values($userBonus->firstErrors)[0] ?? "");
+        }
+
+        return true;
+    }
 }
\ No newline at end of file
index 01bcab5740b9abfcc17504ac2223fce0057c4663..4727721efa5e1d2aeb7e2a38d15d03ffa10b3795 100644 (file)
@@ -20,6 +20,10 @@ class ClaimService extends Model
 {
     public function create(Worker $row)
     {
+        $found = Admin::find()->where(['mobile' => $row->phone])->one() != null;
+        if ($found) {
+            throw new InvalidArgumentException("Пользователь с таким номером телефона уже существует, для создания смены перейдите во вкладку «Календарь смен» —> «Создать смену»");
+        }
         $model = new EmployeeOnShift($row);
         $model->guid = DataHelper::createGuidMy("06");
         $model->created_at = date(DATE_ATOM);
@@ -83,7 +87,7 @@ class ClaimService extends Model
             $exportImportTable->export_val = $model->guid;
             $exportImportTable->save();
 
-            $timeslot = Timetable::TIMESLOT_FREELANCE;
+            $timeslot = Timetable::TIMESLOT_WORK;
         } else {
             $admin = $oldAdmin;
             // Чтобы при создании подработчиков в 1с по guid заявки находился admin,
@@ -112,6 +116,7 @@ class ClaimService extends Model
             $timetable->time_end = $model->shift_type == 1 ? '20:00:00' : '08:00:00';
             $timetable->work_time = 12;
 //            $timetable->price_hour = $model->price;
+            $timetable->salary_shift = $model->salary_shift;
             $timetable->slot_type_id = $timeslot;
             $timetable->date_add = date('Y-m-d H:i:s');
             $timetable->status = Timetable::STATUS_PENDING;
index 9a87911466f25fa4cd9742c270085963132b7ef9..ba233f222559979c0a8293c2fad76364a480c616 100644 (file)
@@ -35,10 +35,14 @@ class IncomeService
         $baseIncome = [];
         foreach ($plans as $plan) {
             /* @var $plan Timetable */
+            if (!isset($workHoursPerPlanId[$plan->id])) {
+                continue;
+            }
             // получаем отработку со временем для каждой запланированной смены
             $baseIncome [] = [
                 'date' => $plan->date,
                 'shift_id' => $plan->shift_id,
+                'salary_shift' => $plan->salary_shift,
                 'price' => $plan->shift_id == 1 ? 125 : 145,
                 'work_hours' => $workHoursPerPlanId[$plan->id] ?? 0, // если план есть, а факта нет, то 0 чаов отработано
                 'in_shift' => count($plan->checkIns) == 1,
diff --git a/erp24/api3/core/services/NotifiableService.php b/erp24/api3/core/services/NotifiableService.php
new file mode 100644 (file)
index 0000000..b865fdf
--- /dev/null
@@ -0,0 +1,69 @@
+<?php
+
+namespace yii_app\api3\core\services;
+
+use yii\db\Exception;
+use yii\db\Expression;
+use yii\helpers\ArrayHelper;
+use yii_app\records\NotifiableUser;
+use yii_app\records\UsersBonus;
+
+class NotifiableService
+{
+    /**
+     * @throws \yii\base\Exception
+     * @throws Exception
+     */
+    public function getExpiredBonuses() {
+        $buffer = [];
+        foreach (['+1 month', '+1 week'] as $timePeriod) {
+            $userBonus = UsersBonus::find()->where(['between', 'date_end',
+                date("Y-m-d 00:00:00", strtotime($timePeriod, time())),
+                date("Y-m-d 23:59:59", strtotime($timePeriod, time()))])
+                ->andWhere(['tip' => 'plus'])->all();
+            foreach ($userBonus as $bonus) {
+                /** @var $bonus UsersBonus */
+                $percent = $bonus->price > $bonus->bonus ? floor($bonus->bonus / $bonus->price * 100) : 0;
+                $is_cashback = $percent > 19;
+                $buffer[$bonus->phone] =[
+                    "date" => date("c", strtotime($bonus->date_end)),
+                    "amount" => $bonus->bonus,
+                    "is_cashback" => $is_cashback
+                ];
+            }
+        }
+
+        $userBonuses = UsersBonus::find()->select(['phone', 'sum(if(tip=\'plus\', bonus, -bonus)) as sum'])
+            ->where(['in', 'phone', array_keys($buffer)])
+            ->andWhere(['<', 'date_start', new Expression('NOW()')])
+            ->andWhere(['>', 'date_end', new Expression('NOW()')])
+            ->groupBy(['phone'])->all();
+        $buffer2 = ArrayHelper::map($userBonuses, 'phone', 'sum');
+
+        $phones = [];
+        foreach ($buffer as $phone => $data) {
+            $data['amount'] = min($data['amount'], $buffer2[$phone]);
+            if ($data['amount'] < 1) {
+                continue;
+            }
+            $phones [] = ArrayHelper::merge(
+                ["phone" => "" . $phone, "balance" => $buffer2[$phone]],
+                $data
+            );
+        }
+
+        return $phones;
+    }
+
+    /**
+     * @throws \yii\base\Exception
+     * @throws Exception
+     */
+    public function getGetFirstSaleUsers() {
+        // Приготовиться к копированию
+        NotifiableUser::updateAll(['status' => 1], ['status' => 0]);
+        $notifiableUsers = NotifiableUser::find()->where(['status' => 1])->asArray()->all();
+        NotifiableUser::deleteAll(['status' => 1]);
+        return $notifiableUsers;
+    }
+}
\ No newline at end of file
diff --git a/erp24/api3/core/services/ReportService.php b/erp24/api3/core/services/ReportService.php
new file mode 100644 (file)
index 0000000..70a6364
--- /dev/null
@@ -0,0 +1,359 @@
+<?php
+
+namespace yii_app\api3\core\services;
+
+use yii\db\Exception;
+use yii\db\Expression;
+use yii\helpers\ArrayHelper;
+use yii_app\api3\modules\v1\models\timetable\Timetable;
+use yii_app\records\AdminPayrollDays;
+use yii_app\records\CityStore;
+use yii_app\records\ExportImportTable;
+use yii_app\records\Products1c;
+use yii_app\records\ProductsClass;
+use yii_app\records\Sales;
+use yii_app\records\StoreVisitors;
+use yii_app\records\WriteOffs;
+use yii_app\records\WriteOffsErp;
+
+class ReportService
+{
+    /**
+     * @throws \yii\base\Exception
+     * @throws Exception
+     */
+    public function show($data) {
+        $currentDate = $data->date_start;
+        $reports = [];
+        while ($currentDate <= $data->date_end) {
+            $report = [
+                "date" => $currentDate,
+                "shift_type" => $data->shift_type,
+            ];
+
+            $shift_id = $data->shift_type == 0 ? [1, 2, 5, 8] : ($data->shift_type == 1 ? [1, 5, 8] : [2]);
+
+            $timetablesMonth = Timetable::find()->alias('t')->select(['admin_id', 'a.name as adminName', 't.store_id', 't.shift_id'])
+                ->innerJoin('admin a', 'admin_id = a.id')
+                ->where(['t.store_id' => $data->stores])
+                ->andWhere(['>=', 'date', date("Y-m-01", strtotime($currentDate))])
+                ->andWhere(['<=', 'date', $currentDate])
+                ->andWhere(['shift_id' => $shift_id, 'tabel' => 0, 'slot_type_id' => Timetable::TIMESLOT_WORK])
+                ->asArray()->all();
+
+            $timetables = Timetable::find()->alias('t')->select(['admin_id', 'a.name as adminName', 't.store_id', 't.shift_id'])
+                ->innerJoin('admin a', 'admin_id = a.id')
+                ->where(['t.store_id' => $data->stores])
+                ->andWhere(['date' => $currentDate, 'tabel' => 0])
+                ->andWhere(['shift_id' => $shift_id, 'slot_type_id' => Timetable::TIMESLOT_WORK])
+                ->asArray()->all();
+
+            $adminIdsMonth = ArrayHelper::getColumn($timetablesMonth, 'admin_id');
+            $adminIds = ArrayHelper::getColumn($timetables, 'admin_id');
+
+            $adminPayrollDaysMonth = AdminPayrollDays::find()->select(["FLOOR(SUM(day_payroll)) as total", "store_id"])
+                ->where(['>=', 'date', date("Y-m-01", strtotime($currentDate))])
+                ->andWhere(['<=', 'date', $currentDate])
+                ->andWhere(['admin_id' => $adminIdsMonth])
+                ->groupBy(['store_id'])
+                ->indexBy('store_id')
+                ->asArray()->all();
+
+            $adminPayrollDays = AdminPayrollDays::find()->select(["FLOOR(SUM(day_payroll)) as total", "store_id"])
+                ->where(['date' => $currentDate, 'admin_id' => $adminIds])
+                ->groupBy(['store_id'])
+                ->indexBy('store_id')
+                ->asArray()->all();
+
+            $date_start = $data->shift_type == 2 ?
+                date("Y-m-d 20:00:00", strtotime($currentDate)) :
+                date("Y-m-d 08:00:00", strtotime($currentDate));
+            $date_end = $data->shift_type == 1 ?
+                date("Y-m-d 20:00:00", strtotime($currentDate)) :
+                date("Y-m-d 08:00:00", strtotime("+1 day", strtotime($currentDate)));
+
+            $storeVisitorsQuery = StoreVisitors::find()
+                ->select([
+                    'counter' => new \yii\db\Expression("SUM(counter)"),
+                    'store_id',
+                ]);
+
+            if ($data->shift_type == 1) {
+                $storeVisitorsQuery->andWhere(['>=', 'date_hour', 8])->andWhere(['<=', 'date_hour', 20])
+                    ->andWhere(['date' => date("Y-m-d", strtotime($currentDate))]);
+            }
+            if ($data->shift_type == 2) {
+                $storeVisitorsQuery->andWhere([
+                    'or',
+                    [
+                        'and',
+                        ['>=', 'date_hour', 20],
+                        ['<=', 'date_hour', 23],
+                        ['date' => date("Y-m-d", strtotime($currentDate))]
+                    ],
+                    [
+                        'and',
+                        ['>=', 'date_hour', 0],
+                        ['<=', 'date_hour', 7],
+                        ['date' => date("Y-m-d", strtotime("+1 day", strtotime($currentDate)))]
+                    ],
+                ]);
+            }
+            if ($data->shift_type == 0) {
+                $storeVisitorsQuery->andWhere([
+                    'or',
+                    [
+                        'and',
+                        ['>=', 'date_hour', 8],
+                        ['<=', 'date_hour', 23],
+                        ['date' => date("Y-m-d", strtotime($currentDate))]
+                    ],
+                    [
+                        'and',
+                        ['>=', 'date_hour', 0],
+                        ['<=', 'date_hour', 7],
+                        ['date' => date("Y-m-d", strtotime("+1 day", strtotime($currentDate)))]
+                    ],
+                ]);
+            }
+
+            $storeVisitors = $storeVisitorsQuery->groupBy(['store_id'])->asArray()->all();
+            $storeVisitorsByStore = ArrayHelper::map($storeVisitors, 'store_id', 'counter');
+
+            $salesPhones = Sales::find()->alias('s')->select(["DISTINCT(s.phone)"])
+                ->where(['between', 's.date', $date_start, $date_end])
+                ->andWhere(['IS NOT', 's.phone', new Expression('NULL')])
+                ->andWhere(['s.store_id' => $data->stores])
+                ->asArray()->all();
+
+            $sales = Sales::find()->alias('s')->select(["COUNT(*) as cnt",
+                "sum(IF(operation='Продажа',s.summ,IF(operation='Возврат',-s.summ,0))) as total",
+                "sum(IF(IfNull(s.phone,-1)=-1,0,1)) as bonusUserCount",
+                "sum(IF(IfNull(s.phone,-1)!=-1 AND (IfNull(u.sale_cnt, -1) = -1 OR u.sale_cnt < 2), 1, 0)) as newBonusUserCount",
+                "sum(IF(IfNull(s.phone,-1)!=-1 AND u.sale_cnt > 1, 1, 0)) as repeatBonusUserCount",
+                "s.store_id",
+                "s.admin_id"])
+                ->leftJoin('users u', 'u.phone = s.phone AND u.phone IN (\''
+                    . implode('\',\'', ArrayHelper::getColumn($salesPhones, 'phone')) .'\')')
+                ->where(['between', 's.date', $date_start, $date_end])
+                ->andWhere(['s.store_id' => $data->stores])
+                ->groupBy(['s.store_id', 's.admin_id'])->asArray()->all();
+
+            $salesMapArr = [];
+            foreach ($sales as $sale) {
+                $salesMapArr[$sale['store_id']][] = $sale;
+            }
+
+            $writeOffsMonth = WriteOffs::find()->select(['sum(summ) as total', 'store_id'])
+                ->where(['between', 'date', date("Y-m-01", strtotime($currentDate)), $date_end])
+                ->andWhere(['type' => WriteOffsErp::WRITE_OFFS_TYPE_BRAK])
+                ->groupBy(['store_id'])
+                ->indexBy(['store_id'])
+                ->asArray()->all();
+
+            $writeOffs = WriteOffs::find()->select(['sum(summ) as total', 'store_id'])
+                ->where(['between', 'date', $date_start, $date_end])
+                ->andWhere(['type' => WriteOffsErp::WRITE_OFFS_TYPE_BRAK])
+                ->groupBy(['store_id'])
+                ->indexBy(['store_id'])
+                ->asArray()->all();
+
+            $eitMonth = ExportImportTable::find()->where(['export_val' => array_keys($writeOffsMonth)])
+                ->select(['entity_id', 'export_val'])
+                ->where(['export_id' => 1, 'entity' => 'city_store'])
+                ->indexBy(['export_val'])
+                ->asArray()->all();
+
+            $totalWriteOffsByStoreId = [];
+            foreach ($writeOffs as $guid => $value) {
+                $totalWriteOffsByStoreId[$eitMonth[$guid]['entity_id']] = $value['total'];
+            }
+
+            $totalWriteOffsByStoreIdMonth = [];
+            foreach ($writeOffsMonth as $guid => $value) {
+                $totalWriteOffsByStoreIdMonth[$eitMonth[$guid]['entity_id']] = $value['total'];
+            }
+
+            $specificSales = [];
+            foreach (['matrix', 'wrap', 'services', 'potted'] as $productTip) {
+                $productsClass = ProductsClass::find()->select(['category_id', 'tip'])
+                    ->where(['tip' => $productTip])
+                    ->indexBy('category_id')
+                    ->asArray()->all();
+
+                $products1c = Products1c::find()->select(['id', 'parent_id', 'name'])
+                    ->where(['parent_id' => array_keys($productsClass), 'tip' => 'products'])
+                    ->indexBy(['id'])
+                    ->asArray()->all();
+
+                $salesMatrix = Sales::find()->alias('s')->select([
+                    "sum(IF(operation='Продажа',p.summ,IF(operation='Возврат',-p.summ,0))) as total",
+                    's.store_id', 's.admin_id'])
+                    ->leftJoin('sales_products p', 'p.check_id = s.id')
+                    ->where(['between', 's.date', $date_start, $date_end])
+                    ->andWhere(['operation' => Sales::OPERATION_SALE])
+                    ->andWhere(['p.product_id' => array_keys($products1c)])
+                    ->groupBy(['s.store_id', 's.admin_id'])
+                    ->asArray()->all();
+
+                $specificSales[$productTip] = $salesMatrix;
+            }
+
+            $adminNames = [];
+            foreach ($timetables as $timetable) {
+                $adminNames[$timetable['store_id']][] = [
+                    'id' => $timetable['admin_id'],
+                    'name' => $timetable['adminName'],
+                    'shift_id' => $timetable['shift_id'],
+                ];
+            }
+
+            $storeVisitorsQuantityTotal = 0;
+            $storeSaleQuantityTotal = 0;
+            $storeSaleTotalTotal = 0;
+            $storeSaleBonusCountTotal = 0;
+            $storeSaleNewBonusCountTotal = 0;
+            $storeSaleRepeatBonusCountTotal = 0;
+            $totalWriteOffsPerDateTotal = 0;
+            $totalWriteOffsPerMonthTotal = 0;
+            $totalPayrollDaysTotal = 0;
+            $totalPayrollMonthTotal = 0;
+            $totalMatrixPerDayTotal = 0;
+            $totalWrapPerDayTotal = 0;
+            $totalServicePerDayTotal = 0;
+            $totalPottedPerDayTotal = 0;
+
+            $stores = CityStore::find()->where(['id' => $data->stores])->all();
+            foreach ($stores as $store) {
+                /** @var CityStore $store */
+                $storeSaleArr = $salesMapArr[$store->id] ?? [];
+                $storeVisitorsQuantity = (int)($storeVisitorsByStore[$store->id] ?? 0);
+                $storeSaleQuantity = 0;
+                $storeSaleTotal = 0;
+                $storeSaleBonusCount = 0;
+                $storeSaleNewBonusCount = 0;
+                $storeSaleRepeatBonusCount = 0;
+                $storeSaleByAdminId = [];
+                foreach ($storeSaleArr as $storeSale) {
+                    $storeSaleByAdminId[$storeSale['admin_id']] = $storeSale;
+                    $storeSaleQuantity += (int)$storeSale['cnt'];
+                    $storeSaleTotal += (int)$storeSale['total'];
+                    $storeSaleBonusCount += (int)$storeSale['bonusUserCount'];
+                    $storeSaleNewBonusCount += (int)$storeSale['newBonusUserCount'];
+                    $storeSaleRepeatBonusCount += (int)$storeSale['repeatBonusUserCount'];
+                }
+
+                $storeVisitorsQuantityTotal += $storeVisitorsQuantity;
+                $storeSaleQuantityTotal += $storeSaleQuantity;
+                $storeSaleTotalTotal += $storeSaleTotal;
+                $storeSaleBonusCountTotal += $storeSaleBonusCount;
+                $storeSaleNewBonusCountTotal += $storeSaleNewBonusCount;
+                $storeSaleRepeatBonusCountTotal += $storeSaleRepeatBonusCount;
+
+                if (isset($adminNames[$store->id])) {
+                    foreach ($adminNames[$store->id] as &$adminRecord) {
+                        $adminRecord["sale_quantity"] = (int)($storeSaleByAdminId[$adminRecord['id']]['cnt'] ?? 0);
+                        $adminRecord["sale_total"] = (int)($storeSaleByAdminId[$adminRecord['id']]['total'] ?? 0);
+                        $adminRecord["sale_avg"] = $adminRecord["sale_quantity"] > 0 ? floor($adminRecord["sale_total"] / $adminRecord["sale_quantity"]) : 0;
+                        $adminRecord["bonus_user_count"] = (int)($storeSaleByAdminId[$adminRecord['id']]['bonusUserCount'] ?? 0);
+                        $adminRecord["bonus_user_per_sale_percent"] = $adminRecord["sale_quantity"] > 0 ? floor($adminRecord["bonus_user_count"] / $adminRecord["sale_quantity"] * 100) : 0;
+                        $adminRecord["bonus_new_user_count"] = (int)($storeSaleByAdminId[$adminRecord['id']]['newBonusUserCount'] ?? 0);
+                        $adminRecord["bonus_repeat_user_count"] = (int)($storeSaleByAdminId[$adminRecord['id']]['repeatBonusUserCount'] ?? 0);
+                    }
+                }
+
+                $totalWriteOffsPerDate  = (int)($totalWriteOffsByStoreId[$store->id] ?? 0);
+                $totalWriteOffsPerMonth = (int)($totalWriteOffsByStoreIdMonth[$store->id] ?? 0);
+                $totalWriteOffsPerDateTotal += $totalWriteOffsPerDate;
+                $totalWriteOffsPerMonthTotal += $totalWriteOffsPerMonth;
+
+                $totalPayrollDays = (int)($adminPayrollDays[$store->id]['total'] ?? 0);
+                $totalPayrollMonth = (int)($adminPayrollDaysMonth[$store->id]['total'] ?? 0);
+
+                $totalPayrollDaysTotal += $totalPayrollDays;
+                $totalPayrollMonthTotal += $totalPayrollMonth;
+
+                $totalSpecificPerDay = [];
+                foreach (['matrix', 'wrap', 'services', 'potted'] as $spec) {
+                    $totalSpecificPerDay[$spec] = 0;
+                    if (isset($adminNames[$store->id])) {
+                        foreach ($adminNames[$store->id] as &$adminRecord) {
+                            $adminRecord["total_" . $spec . "_per_day"] = 0;
+                        }
+                    }
+                    foreach ($specificSales[$spec] as $specificSale) {
+                        if ($specificSale['store_id'] == $store->id) {
+                            $totalSpecificPerDay[$spec] += $specificSale['total'];
+                        }
+                        if (isset($adminNames[$store->id])) {
+                            foreach ($adminNames[$store->id] as &$adminRecord) {
+                                if ($specificSale['admin_id'] == $adminRecord['id']) {
+                                    $adminRecord["total_" . $spec . "_per_day"] = (int)$specificSale['total'];
+                                }
+                            }
+                        }
+                    }
+                }
+                $totalMatrixPerDay = $totalSpecificPerDay['matrix'];
+                $totalWrapPerDay = $totalSpecificPerDay['wrap'];
+                $totalServicePerDay = $totalSpecificPerDay['services'];
+                $totalPottedPerDay = $totalSpecificPerDay['potted'];
+
+                $totalMatrixPerDayTotal += $totalMatrixPerDay;
+                $totalWrapPerDayTotal += $totalWrapPerDay;
+                $totalServicePerDayTotal += $totalServicePerDay;
+                $totalPottedPerDayTotal += $totalPottedPerDay;
+
+
+                $reportStore = [
+                    "name" => $store->name,
+                    "id" => $store->id,
+                    "admins" => $adminNames[$store->id] ?? [],
+                    "visitors_quantity" => $storeVisitorsQuantity,
+                    "sale_quantity" => $storeSaleQuantity,
+                    "sale_total" => $storeSaleTotal,
+                    "sale_avg" => $storeSaleQuantity > 0 ? floor($storeSaleTotal / $storeSaleQuantity) : 0,
+                    "bonus_user_count" => $storeSaleBonusCount,
+                    "bonus_user_per_sale_percent" => $storeSaleQuantity > 0 ? floor($storeSaleBonusCount / $storeSaleQuantity * 100) : 0,
+                    "bonus_new_user_count" => $storeSaleNewBonusCount,
+                    "bonus_repeat_user_count" => $storeSaleRepeatBonusCount,
+                    "total_write_offs_per_date_percent" => $storeSaleTotal > 0 ? floor($totalWriteOffsPerDate / $storeSaleTotal * 100) : 0,
+                    "total_write_offs_per_date" => $totalWriteOffsPerDate,
+                    "total_write_offs_per_month" => $totalWriteOffsPerMonth,
+                    "total_payroll_days" => $totalPayrollDays,
+                    "total_payroll_month" => $totalPayrollMonth,
+                    "total_matrix_per_day" => $totalMatrixPerDay,
+                    "total_wrap_per_day" => $totalWrapPerDay,
+                    "total_services_per_day" => $totalServicePerDay,
+                    "total_potted_per_day" => $totalPottedPerDay,
+                ];
+                $report["stores"][] = $reportStore;
+            }
+
+            $report['total'] = [
+                "visitors_quantity" => $storeVisitorsQuantityTotal,
+                "sale_quantity" => $storeSaleQuantityTotal,
+                "sale_total" => $storeSaleTotalTotal,
+                "sale_avg" => $storeSaleQuantityTotal > 0 ? floor($storeSaleTotalTotal / $storeSaleQuantityTotal) : 0,
+                "bonus_user_count" => $storeSaleBonusCountTotal,
+                "bonus_user_per_sale_percent" => $storeSaleQuantityTotal > 0 ? floor($storeSaleBonusCountTotal / $storeSaleQuantityTotal * 100) : 0,
+                "bonus_new_user_count" => $storeSaleNewBonusCountTotal,
+                "bonus_repeat_user_count" => $storeSaleRepeatBonusCountTotal,
+                "total_write_offs_per_date_percent" => $storeSaleTotalTotal > 0 ? floor($totalWriteOffsPerDateTotal / $storeSaleTotalTotal * 100) : 0,
+                "total_write_offs_per_date" => $totalWriteOffsPerDateTotal,
+                "total_write_offs_per_month" => $totalWriteOffsPerMonthTotal,
+                "total_payroll_days" => $totalPayrollDaysTotal,
+                "total_payroll_month" => $totalPayrollMonthTotal,
+                "total_matrix_per_day" => $totalMatrixPerDayTotal,
+                "total_wrap_per_day" => $totalWrapPerDayTotal,
+                "total_services_per_day" => $totalServicePerDayTotal,
+                "total_potted_per_day" => $totalPottedPerDayTotal,
+            ];
+
+            $reports[] = $report;
+            $currentDate = date("Y-m-d", strtotime("+1 day", strtotime($currentDate)));
+        }
+
+        return $reports;
+    }
+}
\ No newline at end of file
index 0560f09f6fa2b72f81034c4e391465f0303d2869..af2bfb53b8313f59bb9a267fae3e44aaf1d9a83a 100644 (file)
@@ -12,6 +12,7 @@ use yii_app\records\Prices;
 use yii_app\records\Products1c;
 use yii_app\records\Sales;
 use yii_app\records\SalesProducts;
+use yii_app\records\StoreDynamic;
 use yii_app\services\LogService;
 
 class StoreService
@@ -294,4 +295,20 @@ class StoreService
 
         return ['response' => true];
     }
+
+    public function getClusters() {
+        $storeDynamic = StoreDynamic::find()->alias('s')->select(['s.store_id as id', 's.value_int as cluster', 'c.name'])
+            ->innerJoin("city_store c", "c.id = s.store_id")
+            ->asArray()->all();
+
+        $storesPerCluster = [];
+        foreach ($storeDynamic as $data) {
+            $storesPerCluster[$data['cluster']][] = ['id' => $data['id'], 'name' => $data['name']];
+        }
+        $result = [];
+        foreach ($storesPerCluster as $key => $data) {
+            $result[] = ['id' => $key, 'stores' => $data];
+        }
+        return $result;
+    }
 }
\ No newline at end of file
index 49340ba22cb6460a9cfdcb28091e45c005ea6c2a..a91eb490c673167a60eec990f28a808614fbfc6b 100644 (file)
@@ -10,6 +10,7 @@ use yii_app\api3\modules\v1\models\timetable\Timetable;
 use yii_app\api3\modules\v1\requests\timetable\Fact;
 use yii_app\records\AdminCheckin;
 use yii_app\records\AdminDevice;
+use yii_app\records\AdminGroup;
 use yii_app\records\TimetableV3;
 use yii_app\records\TimetableWorkbot;
 
@@ -66,7 +67,7 @@ class TimetableService
             $checkIn->lon = $data->lon;
             $checkIn->photo = $imagePath;
             $checkIn->device_id = AdminDevice::findOne(['admin_id' => $timetable->admin_id])->id ?? 0;
-            $checkIn->type_id = AdminCheckin::TYPE_START;
+            $checkIn->type_id = $checkIn->d_id == AdminGroup::GROUP_ADMINISTRATORS ? AdminCheckin::TYPE_APPEAR : AdminCheckin::TYPE_START;
             $checkIn->status = 0;
             $checkIn->save();
             if ($checkIn->getErrors()) {
@@ -139,7 +140,7 @@ class TimetableService
         $checkIn->photo = $imagePath;
         $checkIn->status = 0;
         $checkIn->device_id = AdminDevice::findOne(['admin_id' => $timetable->admin_id])->id ?? 0;
-        $checkIn->type_id = AdminCheckin::TYPE_END;
+        $checkIn->type_id = $checkIn->d_id == AdminGroup::GROUP_ADMINISTRATORS ? AdminCheckin::TYPE_APPEAR : AdminCheckin::TYPE_END;
         $checkIn->save();
         if ($checkIn->getErrors()) {
             throw new \Exception(Json::encode($checkIn->getErrors()));
@@ -148,6 +149,60 @@ class TimetableService
         return true;
     }
 
+    /**
+     * @throws \yii\base\Exception
+     * @throws Exception
+     */
+    public function appear($data) {
+        /** @var $data Fact */
+        $timetable = Timetable::findOne(['id' => $data->plan_id, 'tabel' => 0]);
+        if(!$timetable) {
+            throw new NotFoundHttpException("План не найден");
+        }
+
+        if ($timetable->date != date("Y-m-d") &&
+            $timetable->date != date("Y-m-d", strtotime("-1 day", time()))) {
+            throw new InvalidArgumentException("План ссылается на другую дату");
+        }
+
+        $currentDate = date('Y-m-d H:i:s'); // вынести в хелпер
+        $transaction = \Yii::$app->db->beginTransaction();
+        try {
+
+            $imagePath = $data->uploadImage($timetable->admin_id);
+            if (!$imagePath) {
+                throw new InvalidArgumentException("Не удалось загрузить картинку");
+            }
+
+            $checkIn = new AdminCheckin();
+            $checkIn->admin_id = $timetable->admin_id;
+            $checkIn->plan_id = $timetable->id;
+            $checkIn->store_id = $timetable->store_id;
+            $checkIn->ball = 5;
+            $checkIn->comment = "";
+            $checkIn->d_id = $timetable->admin->group_id;
+            $checkIn->date = $timetable->date;
+            $checkIn->time = $currentDate;
+            $checkIn->lat = $data->lat;
+            $checkIn->lon = $data->lon;
+            $checkIn->photo = $imagePath;
+            $checkIn->device_id = AdminDevice::findOne(['admin_id' => $timetable->admin_id])->id ?? 0;
+            $checkIn->type_id = AdminCheckin::TYPE_APPEAR;
+            $checkIn->status = 0;
+            $checkIn->save();
+            if ($checkIn->getErrors()) {
+                throw new \Exception(Json::encode($checkIn->getErrors()));
+            }
+
+            $transaction->commit();
+        } catch (Exception $e) {
+            $transaction->rollBack();
+            throw $e;
+        }
+
+        return $timetable;
+    }
+
     public function delete($plan_id, $comment, $removed_by) {
         $timetable = Timetable::find()->where(['id' => $plan_id])->one();
         /* @var $timetable Timetable */
index 95b8909a97a409a9f28c577d7055ebf2cac95c69..2644b14d7d04fd0e0565c61eecfc1dc477f42c52 100644 (file)
@@ -9,6 +9,8 @@ use yii_app\api3\core\services\ClientService;
 use yii_app\api3\core\services\EmployeeService;
 use yii_app\api3\core\services\IncomeService;
 use yii_app\api3\core\services\KikService;
+use yii_app\api3\core\services\NotifiableService;
+use yii_app\api3\core\services\ReportService;
 use yii_app\api3\core\services\StoreService;
 use yii_app\api3\core\services\TimetableService;
 
@@ -45,4 +47,12 @@ trait ServiceTrait
     public function getKikService() {
         return Service::create(KikService::class);
     }
+
+    public function getNotifiableService() {
+        return Service::create(NotifiableService::class);
+    }
+
+    public function getReportService() {
+        return Service::create(ReportService::class);
+    }
 }
\ No newline at end of file
index 2fcb9a1ab84e081d451fcd99905348334fbba112..17ec946d7a857e0d7cd904c1117e2da8667afca9 100644 (file)
@@ -8,10 +8,12 @@ class Util
     {
         $phone = $phone ?: "";
 
+        $phone = preg_replace("/\D/", '', $phone);
+
         // костыль для русских номеров
-        if (str_starts_with($phone, "89") && strlen($phone) == 11)
+        if (str_starts_with($phone, "89"))
             $phone = "7" . substr($phone, 1);
 
-        return preg_replace("/\D/", '', $phone);
+        return $phone;
     }
 }
\ No newline at end of file
index b586c6b87475f9db4cc6ac85a5af090f8fe82874..cbd00a7e4bb3f9734a7d12ebed8494d28ade04f4 100644 (file)
@@ -3,7 +3,9 @@
 namespace yii_app\api3\modules\v1\controllers;
 
 use yii\db\Query;
+use yii\helpers\ArrayHelper;
 use yii_app\api3\modules\v1\models\Admin;
+use yii_app\records\AdminGroup;
 
 class AdminController extends \yii_app\api3\controllers\ActiveController
 {
@@ -23,9 +25,26 @@ class AdminController extends \yii_app\api3\controllers\ActiveController
             'class' => \yii\data\ActiveDataFilter::class,
             'searchModel' => $this->modelClass,
         ];
+        $actions['index']['prepareSearchQuery'] = function ($query, $requestParams) {
+            return $query->andFilterWhere(['not in', 'group_id', [AdminGroup::GROUP_FIRED]]);
+        };
 
         unset($actions['create'], $actions['delete'], $actions['update']);
 
         return $actions;
     }
+
+    public function actionEmployees() {
+        $admins = Admin::find()->select(['id', 'name', 'mobile as phone'])
+            ->where(['in', 'group_id', AdminGroup::getGroupsForEmployeeOnCashbox()])->asArray()->all();
+        $results = [];
+        foreach ($admins as $admin) {
+            $results []= [
+                'id' => (int)$admin['id'],
+                'name' => $admin['name'],
+                'phone' => '+7(***)**' . substr($admin['phone'], -4)
+            ];
+        }
+        return $results;
+    }
 }
\ No newline at end of file
index e0e287096eca8b96615bb874057cc391d376c294..4cb3ed685846f40f57f469678dd4405c580a70e4 100644 (file)
@@ -11,6 +11,7 @@ use yii_app\api3\modules\v1\requests\bonus\GetClientInfoInput;
 use yii_app\api3\modules\v1\requests\bonus\ReturnInput;
 use yii_app\api3\modules\v1\requests\bonus\SaleInput;
 use yii_app\api3\modules\v1\requests\bonus\SaveClientInfoInput;
+use yii_app\api3\modules\v1\requests\bonus\BonusWriteOffInput;
 
 /**
  * @property BonusService $bonusService
@@ -164,4 +165,22 @@ class BonusController extends \yii_app\api3\controllers\NoActiveController
 
         return $this->bonusService->bonusAdd($data);
     }
+
+    public function actionWriteOff() {
+        // localhost:8888/v1/bonus/write-off
+        // {
+        //  "phone": "+79200247501",
+        //  "lid_id": "12345",
+        //  "price": 100,
+        //  "bonus": 20,
+        //  "date_start": "2023-06-16",
+        //  "date_end": "2024-01-01 00:00:00"
+        // }
+        $params = \Yii::$app->request->post();
+
+        $model = new BonusWriteOffInput;
+        $data = $this->validate($model, $params);
+
+        return $this->bonusService->bonusWriteOff($data);
+    }
 }
\ No newline at end of file
index 07f4373e3e77e9521b53926019f77eb1a2452893..3a257973bd0f07751e6a811bebe0e2edce7bbda5 100644 (file)
@@ -5,6 +5,7 @@ namespace yii_app\api3\modules\v1\controllers;
 use yii_app\api3\core\services\EmployeeService;
 use yii_app\api3\core\traits\ServiceTrait;
 use yii_app\api3\modules\v1\requests\employee\AtStoreInput;
+use yii_app\records\Timetable;
 
 /**
  * @property EmployeeService $employeeService
@@ -32,4 +33,8 @@ class EmployeeController extends \yii_app\api3\controllers\NoActiveController
 
         return $this->employeeService->atStore($data);
     }
+
+    public function actionSalariesDay() {
+        return Timetable::getSalariesDay();
+    }
 }
\ No newline at end of file
diff --git a/erp24/api3/modules/v1/controllers/NotifiableController.php b/erp24/api3/modules/v1/controllers/NotifiableController.php
new file mode 100644 (file)
index 0000000..5f58041
--- /dev/null
@@ -0,0 +1,24 @@
+<?php
+
+namespace yii_app\api3\modules\v1\controllers;
+
+use yii_app\api3\core\services\NotifiableService;
+use yii_app\api3\core\traits\ServiceTrait;
+
+/**
+ * @property NotifiableService $notifiableService
+ */
+class NotifiableController extends \yii_app\api3\controllers\NoActiveController
+{
+    use ServiceTrait;
+
+    public function actionExpiredBonuses() {
+        // localhost:8888/v1/notifiable/expired-bonuses
+        return $this->notifiableService->getExpiredBonuses();
+    }
+
+    public function actionGetFirstSaleUsers() {
+        // localhost:8888/v1/notifiable/get-first-sale-users
+        return $this->notifiableService->getGetFirstSaleUsers();
+    }
+}
\ No newline at end of file
diff --git a/erp24/api3/modules/v1/controllers/ReportController.php b/erp24/api3/modules/v1/controllers/ReportController.php
new file mode 100644 (file)
index 0000000..ca77e70
--- /dev/null
@@ -0,0 +1,49 @@
+<?php
+
+namespace yii_app\api3\modules\v1\controllers;
+
+use yii\helpers\Json;
+use yii_app\api3\core\services\ReportService;
+use yii_app\api3\core\traits\ServiceTrait;
+use yii_app\api3\modules\v1\requests\report\ReportInput;
+use yii_app\records\ApiLogs;
+
+/**
+ * @property ReportService $reportService
+ */
+class ReportController extends \yii_app\api3\controllers\NoActiveController
+{
+    use ServiceTrait;
+
+    public function actionShow() {
+        // localhost:8888/v1/report/Show
+        // {
+        //   "stores": [1,2,3],
+        //   "date_start": "2024-02-15",
+        //   "date_end": "2024-02-16"
+        //   "shift_type": 1 // 1 - дневная, 2 - ночная, 0 - дневная и ночная смена вместе
+        // }
+        $params = \Yii::$app->request->post();
+
+        $model = new ReportInput;
+        $data = $this->validate($model, $params);
+
+        $result = $this->reportService->show($data);
+
+        $apiLogs = new ApiLogs;
+        $apiLogs->url = \Yii::$app->request->url;
+        $apiLogs->request_id = "";
+        $apiLogs->date = date('Y-m-d H:i:s');
+        $apiLogs->content = Json::encode($data);
+        $apiLogs->hash_content = "";
+        $apiLogs->result = Json::encode($result);
+        $apiLogs->status = 0;
+        $apiLogs->store_id = "report_show";
+        $apiLogs->seller_id = "";
+        $apiLogs->phone = "";
+        $apiLogs->ip = "127.0.0.1";
+        $apiLogs->save();
+
+        return $result;
+    }
+}
\ No newline at end of file
index 9fbe8cc63ca61cae9718d5f115f278b130f56550..6edc0aafa5b568adebc5b88a52fd3c424f8c47ca 100644 (file)
@@ -115,4 +115,8 @@ class StoreController extends \yii_app\api3\controllers\ActiveController
 
         return $this->storeService->assemblies($data);
     }
+
+    public function actionGetClusters() {
+        return $this->storeService->getClusters();
+    }
 }
\ No newline at end of file
index 3749b74a17e00fc7c11677becf805136cf5ba751..e0b0a9de4a608cf92a7bc3e6a71b31f011478a1d 100644 (file)
@@ -48,8 +48,6 @@ class WorkerController extends \yii_app\api3\controllers\ActiveController
         $params = Yii::$app->request->bodyParams;
         $data = $this->validate(new Worker(), $params);
 
-        $data->phone = Util::phoneNormalizer($data->phone);
-
         $this->claimService->create($data);
 
         return true;
index 66b84fc70ec42aee6157e4d758e8842075ddf96d..6585682a869f5bbca7d8f1030d6d74622c21d9ee 100644 (file)
@@ -63,4 +63,15 @@ class FactController extends ActiveController
 
         return $this->timetableService->close($data);
     }
+
+    public function actionAppear()
+    {
+        $params = \Yii::$app->request->post();
+
+        $model = new Fact();
+        $model->image = UploadedFile::getInstanceByName('image');
+        $data = $this->validate($model, $params);
+
+        return $this->timetableService->appear($data);
+    }
 }
\ No newline at end of file
index 42f73b5f0e1d8e4f3d7c66481ed9e41a5235303c..c1fc8722d08463b85f54ffc1785d9a94b1e35dde 100644 (file)
@@ -21,6 +21,8 @@ class Store extends Products1c
         return [
             'id',
             'name' => fn($m) => mb_substr($m->name, 3),
+            'city_store_id' => fn($m) => $m->store ? $m->store->id : null,
+            'tg_chat_id' => fn($m) => $m->store ? (!empty($m->store->tg_chat_id) ? $m->store->tg_chat_id : null) : null,
 //            'parent_id' => fn($m) => intval($m->parent_id),
 //            'view'
         ];
@@ -30,6 +32,7 @@ class Store extends Products1c
         return [
             'view',
             'workAdmins' => fn($m) => array_map(fn($x) => [
+                'phone' => $x->mobile,
                 'name' => $x->name,
                 'id' => $x->id
             ], $m->workAdmins)
index 5a8d92d2b71772a6dc0b5440158527adf61dee32..481ddf93af08f3762b0b48c788e04a04ca479fa6 100644 (file)
@@ -9,7 +9,7 @@ class OrdersAmo extends \yii_app\records\OrdersAmo
 {
     public static function getDb()
     {
-        return Yii::$app->db2;
+        return Yii::$app->db;
     }
 
     public function rules(): array
index 90716626cc75a22ef6bef88307f2ea02ee29fddb..71ba9352ad1a700f3f0b76d4c57a0465f9eee095 100644 (file)
@@ -21,6 +21,7 @@ class Timetable extends \yii_app\records\TimetableV3
             [['tabel'], 'integer', 'skipOnEmpty' => false],
             [['id', 'shift_id', 'store_id'], 'integer'],
             [['date'], 'date', 'format' => 'yyyy-M-d'],
+            [['salary_shift'], 'in', 'range' => \yii_app\records\Timetable::getSalariesDay(), 'skipOnEmpty' => true],
             [['shift_id'], 'in', 'range' => array_keys(Shift::all()), 'skipOnEmpty' => false],
             [['store_id'], 'exist', 'targetClass' => CityStore::class, 'targetAttribute' => 'id', 'skipOnEmpty' => false],
             [['admin_id', 'admin_id_add'], 'exist', 'targetClass' => Admin::class, 'targetAttribute' => 'id', 'skipOnEmpty' => true],
@@ -138,6 +139,7 @@ class Timetable extends \yii_app\records\TimetableV3
             'admin_id',
             'store_id',
             'shift_id',
+            'salary_shift',
             // 'price' => fn($x) => $x->shift_id == 2 ? 140 : 125,
             'tabel',
             'date',
diff --git a/erp24/api3/modules/v1/requests/bonus/BonusWriteOffInput.php b/erp24/api3/modules/v1/requests/bonus/BonusWriteOffInput.php
new file mode 100644 (file)
index 0000000..8018e7b
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+namespace yii_app\api3\modules\v1\requests\bonus;
+
+use yii\base\Model;
+use yii_app\api3\core\validators\PhoneValidator;
+
+class BonusWriteOffInput extends Model
+{
+    public $phone;
+    public $lid_id;
+    public $price;
+    public $bonus;
+    public $date_start;
+    public $date_end;
+
+    public function rules()
+    {
+        return [
+            [['phone', 'lid_id', 'price', 'bonus'], 'required'],
+            ['phone', PhoneValidator::class],
+            ['lid_id', 'integer'],
+            [['price', 'bonus'], 'number'],
+            [['date_start', 'date_end'], 'datetime', 'format' => "yyyy-MM-dd H:m:s"],
+        ];
+    }
+}
\ No newline at end of file
index d4c5f8a94c8aa802577a64e5dfe3646af334bc0d..18e3509e14f4798288426f9cb27735bcad5a983a 100644 (file)
@@ -3,9 +3,11 @@
 namespace yii_app\api3\modules\v1\requests\claim;
 
 use yii\base\Model;
+use yii_app\api3\core\validators\PhoneValidator;
 use yii_app\records\Admin;
 use yii_app\records\EmployeeOnShift;
 use yii_app\records\Products1c;
+use yii_app\records\Timetable;
 
 class Worker extends Model
 {
@@ -15,6 +17,7 @@ class Worker extends Model
     public $datetime_start;
     public $datetime_end;
     public $price;
+    public $salary_shift;
     public $shift_type;
     public $first_name;
     public $last_name;
@@ -29,13 +32,16 @@ class Worker extends Model
             ['shift_date', 'date', 'format' => "yyyy-MM-dd"],
             ['shift_type', 'in', 'range' => [0, 1, 2]],
             [['first_name', 'last_name'], 'string', 'min' => 2, 'max' => 40],
+            [['first_name', 'last_name'], 'filter', 'filter' => 'trim'],
             ['price', 'number', 'min' => 120, 'max' => 150],
+            [['salary_shift'], 'in', 'range' => Timetable::getSalariesDay(), 'skipOnEmpty' => false],
             [['datetime_start', 'datetime_end'], 'datetime', 'format' => "yyyy-MM-dd H:m:s"],
 
 //            [['guid'], 'unique'],
             ['created_by', 'exist', 'targetClass' => Admin::class, 'targetAttribute' => 'id', 'filter' => ['group_id' => [1, 7, 8, 10, 30, 35, 40, 50, 51, 71]]],
             ['store_id', 'exist', 'targetClass' => Products1c::class, 'targetAttribute' => 'id', 'filter' => ['tip' => 'city_store']],
             ['phone', 'unique', 'targetClass' => EmployeeOnShift::class, 'targetAttribute' => ['phone', 'store_id'], 'filter' => ['status' => EmployeeOnShift::STATUS_INITIAL]],
+            ['phone', PhoneValidator::class],
             ['datetime_start', 'checkDateTimeStart']
         ];
     }
diff --git a/erp24/api3/modules/v1/requests/report/ReportInput.php b/erp24/api3/modules/v1/requests/report/ReportInput.php
new file mode 100644 (file)
index 0000000..0f8465a
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+
+namespace yii_app\api3\modules\v1\requests\report;
+
+use yii\base\Model;
+
+class ReportInput extends Model
+{
+    public $stores;
+    public $date_start;
+    public $date_end;
+    public $shift_type;
+
+    public function rules(): array
+    {
+        return [
+            [['stores', 'date_start', 'date_end', 'shift_type'], 'required'],
+            ['stores', 'each', 'rule' => ['integer']],
+            [['date_start', 'date_end'], 'datetime', 'format' => 'yyyy-M-d'],
+            ['shift_type', 'in', 'range' => [0, 1, 2]]
+        ];
+    }
+}
\ No newline at end of file
index f558fc644978c3d13907d5548c05ce1d21dd7658..8823e5d727f342ded64f6ffdbbd352d385b0fee5 100644 (file)
@@ -33,19 +33,15 @@ class Fact extends Model
     {
         $uploadDir = \Yii::getAlias("@upload-checkin") . "/";
 
-        // можно сделать проверку на mimetype
-        $extension = mb_strtolower(substr($this->image->name, stripos($this->image->name, ".", -5) + 1));
-
-        $dir = date("Y") . "/" . date("m") . "/" . substr($adminId, 0, 2) . "/" . $adminId . "/";
-
-        $filename = date("d-m-H-i-s") . "." . $extension;
-
-        FileHelper::createDirectory($uploadDir . $dir);
-
-        $path = $dir . $filename;
+        $Y = date("Y");
+        $m = date("m");
+        if (!is_dir($uploadDir . "$Y/$m")) {
+            mkdir($uploadDir . "$Y/$m", 0777, true);
+        }
+        $fileName = $adminId . '-' . date("YmdHis") . '.jpg';
 
-        if($this->image->saveAs($uploadDir . $path)) {
-            return $path;
+        if($this->image->saveAs($uploadDir . "$Y/$m/". $fileName)) {
+            return "data/admin/$Y/$m/" . $fileName;
         } else {
             return false;
         }
diff --git a/erp24/controllers/ChartForManagementController.php b/erp24/controllers/ChartForManagementController.php
new file mode 100644 (file)
index 0000000..a139ef9
--- /dev/null
@@ -0,0 +1,622 @@
+<?php
+
+namespace yii_app\controllers;
+
+use Yii;
+use yii\data\ArrayDataProvider;
+use yii\db\Exception;
+use yii\db\Expression;
+use yii\helpers\ArrayHelper;
+use yii\helpers\Json;
+use yii\web\Controller;
+use yii_app\records\Admin;
+use yii_app\records\ChartDataSearch;
+use yii_app\records\WriteOffs;
+
+class ChartForManagementController extends Controller
+{
+    public function actionIndex()
+    {
+        $admin = Admin::findOne(['id' => Yii::$app->user->id]);
+
+        $access_chart = [
+            'mode_level' => [],
+            'mode_shift' => [],
+            'visible' => false,
+        ];
+
+        $access = [
+            'main' => $access_chart,
+            'plan_completed_this_day' => $access_chart,
+            'plan_completed_this_month' => $access_chart,
+            'sales' => $access_chart,
+            'matrix_sales_sum' => $access_chart,
+            'avg_sales_value' => $access_chart,
+            'fot' => $access_chart,
+            'sales_sum_on_admin' => $access_chart,
+            'user_bonus' => $access_chart,
+            'count_sales_in_hour' => $access_chart,
+            'write_offs' => $access_chart,
+        ];
+
+        if (in_array($admin->group_id, [1, 81, 71, 51, 10, 9, 74, 14])) {
+            foreach ($access as $key => &$item) {
+                if (in_array($key, ['avg_sales_value', 'sales', 'user_bonus', 'matrix_sales_sum', 'count_sales_in_hour'])) {
+                    $item['mode_level'] = [
+                        //0 => 'Доставка',
+                        1 => 'Розница',
+                        2 => 'Куст',
+                        3 => 'Магазин'
+                    ];
+
+                    $item['mode_shift'] = [
+                        3 => 'День+Ночь',
+                        1 => 'День',
+                        2 => 'Ночь',
+                        4 => 'Сутки'
+                    ];
+                } else {
+                    $item['mode_level'] = [
+                        1 => 'Розница',
+                        2 => 'Куст',
+                        3 => 'Магазин'
+                    ];
+
+                    $item['mode_shift'] = [
+                        3 => 'День+Ночь',
+                        1 => 'День',
+                        2 => 'Ночь',
+                        //4 => 'Сутки'
+                    ];
+                }
+
+                $item['visible'] = true;
+            }
+
+        } else if (in_array($admin->group_id, [Admin::CLUSTER_MANAGER_GROUP_ID])) {
+            foreach ($access as &$item) {
+                $item['mode_level'] = [
+                    2 => 'Куст',
+                    3 => 'Магазин',
+                ];
+
+                $item['mode_shift'] = [
+                    3 => 'День+Ночь',
+                    1 => 'День',
+                    2 => 'Ночь',
+
+                ];
+
+                $item['visible'] = true;
+            }
+
+        } else if (in_array($admin->group_id, [30, 40])) {
+            foreach ($access as $key => &$item) {
+                $item['mode_level'] = [
+                    3 => 'Магазин',
+                ];
+
+                $item['mode_shift'] = [
+                    1 => 'День',
+                ];
+
+                if ($key != 'plan_completed_this_day' && $key != 'plan_completed_this_month') {
+                    $item['visible'] = true;
+                }
+
+            }
+
+        } else if (in_array($admin->group_id, [35, 72])) {
+            foreach ($access as $key => &$item) {
+                $item['mode_level'] = [
+                    3 => 'Магазин',
+                ];
+
+                $item['mode_shift'] = [
+                    2 => 'Ночь',
+                ];
+
+                if ($key != 'plan_completed_this_day' && $key != 'plan_completed_this_month') {
+                    $item['visible'] = true;
+                }
+
+            }
+
+        } else if (in_array($admin->group_id, [Admin::ADMINISTRATOR_GROUP_ID])) {
+            foreach ($access as &$item) {
+                $item['mode_level'] = [
+                    3 => 'Магазин'
+                ];
+
+                $item['mode_shift'] = [
+                    3 => 'День+Ночь',
+                    1 => 'День',
+                    2 => 'Ночь',
+
+                ];
+
+                $item['visible'] = true;
+            }
+
+        } else {
+            throw new Exception('Нет доступа');
+        }
+
+        return $this->render('index', [
+            'access' => $access
+        ]);
+    }
+
+    public function actionWriteOffPosition()
+    {
+        $admin = Admin::findOne(['id' => Yii::$app->user->id]);
+
+        $access = [
+            'mode_level' => [],
+            'mode_shift' => [],
+            'access_plan' => false,
+        ];
+
+        if (in_array($admin->group_id, [1, 81, 71, 51, 10, 9, 74, 14])) {
+
+            $access['mode_level'] = [
+                1 => 'Розница',
+                2 => 'Куст',
+                3 => 'Магазин'
+            ];
+
+            $access['mode_shift'] = [
+                3 => 'День+Ночь',
+                1 => 'День',
+                2 => 'Ночь',
+
+            ];
+
+            $access['access_plan'] = true;
+
+        } else if (in_array($admin->group_id, [7])) {
+
+            $access['mode_level'] = [
+                2 => 'Куст',
+                3 => 'Магазин',
+            ];
+
+            $access['mode_shift'] = [
+                3 => 'День+Ночь',
+                1 => 'День',
+                2 => 'Ночь',
+            ];
+
+            $access['access_plan'] = true;
+
+        } else if (in_array($admin->group_id, [30, 40])) {
+
+            $access['mode_level'] = [
+                3 => 'Магазин',
+            ];
+
+            $access['mode_shift'] = [
+                1 => 'День',
+            ];
+
+        } else if (in_array($admin->group_id, [35, 72])) {
+
+            $access['mode_level'] = [
+                3 => 'Магазин',
+            ];
+
+            $access['mode_shift'] = [
+                2 => 'Ночь',
+            ];
+
+        } else if (in_array($admin->group_id, [50])) {
+            $access['mode_level'] = [
+                3 => 'Магазин'
+            ];
+
+            $access['mode_shift'] = [
+                3 => 'День+Ночь',
+                1 => 'День',
+                2 => 'Ночь',
+            ];
+
+            $access['access_plan'] = true;
+        } else {
+            throw new Exception('Нет доступа');
+        }
+
+        return $this->render('write-offs-position-chart', [
+            'access' => $access
+        ]);
+    }
+
+    public function actionGetControlDataAjax()
+    {
+        $post_data = Yii::$app->request->post();
+
+        $date_start = date('Y-m-d H:i:s', strtotime($post_data['date_start']));
+        $date_end = date('Y-m-d H:i:s', strtotime($post_data['date_end']));
+
+        $stores = Admin::find()->where(['admin.id' => Yii::$app->user->id])->leftJoin(
+            'store_dynamic',
+            [
+                'OR',
+                ['LIKE', 'admin.store_arr', new Expression('CONCAT("%," , store_dynamic.store_id, ",%")')],
+                ['LIKE', 'admin.store_arr', new Expression('CONCAT("" , store_dynamic.store_id, ",%")')],
+                ['LIKE', 'admin.store_arr', new Expression('CONCAT("%," , store_dynamic.store_id, "")')],
+                ['LIKE', 'admin.store_arr', new Expression('CONCAT("" , store_dynamic.store_id, "")')],
+            ]
+
+        )
+            ->innerJoin('city_store', 'store_dynamic.store_id = city_store.id AND store_dynamic.category = 1')
+            ->select(
+                [
+                    'cluster_name' => 'CONCAT_WS(\' \', \'Куст\', store_dynamic.value_int)',
+                    'cluster_id' => 'store_dynamic.value_int',
+                    'store_id' => 'store_dynamic.store_id',
+                    'store_name' => 'city_store.name',
+                    'date_from' => 'DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')',
+                ]
+            )
+            ->andWhere(
+                [
+                    'OR',
+                    [
+                        'AND',
+                        ['BETWEEN', 'DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d %H:%i:%s\')', $date_start, $date_end],
+                        ['BETWEEN', 'DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d %H:%i:%s\')', $date_start, $date_end],
+                    ],
+                    [
+                        'AND',
+                        ['BETWEEN', 'DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d %H:%i:%s\')', $date_start, $date_end],
+                        ['>=', 'DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d %H:%i:%s\')', $date_end],
+                    ],
+                    [
+                        'AND',
+                        ['<=', 'DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d %H:%i:%s\')', $date_start],
+                        ['BETWEEN', 'DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d %H:%i:%s\')', $date_start, $date_end],
+                    ],
+                    [
+                        'AND',
+                        ['<=', 'DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d %H:%i:%s\')', $date_start],
+                        ['>=', 'DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d %H:%i:%s\')', $date_start],
+                    ],
+                ]
+            )
+            ->orderBy(['store_dynamic.value_int' => SORT_ASC, 'city_store.id' => SORT_ASC])
+            ->asArray()
+            ->all();
+
+        $steps_stores = ArrayHelper::map($stores, 'date_from', 'cluster_name', 'store_name');
+
+        foreach ($steps_stores as $store_name => $step_store) {
+            if (count($step_store) === 1) {
+                unset($steps_stores[$store_name]);
+            }
+        }
+
+        $clusters_unic = [];
+        foreach ($stores as $store) {
+            if (!in_array(['id' => $store['cluster_id'], 'text' => $store['cluster_name']], $clusters_unic)) {
+                $clusters_unic[] = ['id' => $store['cluster_id'], 'text' => $store['cluster_name']];
+            }
+        }
+
+        $store_in_cluster = [];
+        foreach ($stores as $store) {
+            if (!isset($store_in_cluster[$store['cluster_id']])) {
+                $store_in_cluster[$store['cluster_id']]['text'] = $store['cluster_name'];
+            }
+            $store_in_cluster[$store['cluster_id']]['children'][] = ['id' => $store['store_id'], 'text' => $store['store_name']];
+        }
+
+        return Json::encode(['stores_step' => $steps_stores, 'clusters' => $clusters_unic, 'stores_in_cluster' => $store_in_cluster]);
+    }
+
+    public function actionGetDataAjax()
+    {
+        $post_data = Yii::$app->request->post();
+        $chart_data_search = new ChartDataSearch();
+
+        $chart_data_search->mode_level = intval($post_data['mode']);
+        $chart_data_search->attribute_name = $post_data['attribute'];
+        $chart_data_search->date_start = $post_data['date_start'] ?? date('Y-m-d', strtotime('-13 day'));
+        $chart_data_search->date_end = $post_data['date_end'] ?? date('Y-m-d', time());
+        $chart_data_search->cluster_id = $post_data['cluster'];
+        $chart_data_search->store_id = $post_data['store'];
+        $chart_data_search->mode_shift = $post_data['shift'] ?? 3;
+        $chart_data_search->select_cluster = true;
+
+        if ($post_data['attribute'] === 'plan_completed_this_day') {
+            $chart_data_search->date_start = date('Y-m-d', strtotime('first day of this month'));
+            $chart_data_search->date_end = date('Y-m-d', time());
+
+        }
+
+        if ($post_data['attribute'] === 'plan_completed_this_month') {
+            $chart_data_search->date_start = date('Y-m-d', strtotime('first day of this month'));
+            $chart_data_search->date_end = date('Y-m-d', strtotime('last day of this month'));
+
+        }
+
+        if ($post_data['attribute'] === 'write_offs') {
+            $chart_data_search->date_start = date('Y-m-d', strtotime('first day of this month', strtotime($chart_data_search->date_start)));
+            $chart_data_search->mode_shift = 4;
+        }
+
+        $dates = [];
+        $chart_opts = null;
+        $temp_row = ['sales_sum' => 0, 'sum' => 0, 'plan' => 0];
+        $interval_days = (strtotime($chart_data_search->date_end) - strtotime($chart_data_search->date_start)) / (60 * 60 * 24);
+
+        $data_answer = $chart_data_search->attributes_config[$post_data['attribute']];
+
+        if ($post_data['attribute'] === 'write_offs_position') {
+            $answer_query = $chart_data_search->searchWriteOffsItems();
+        }
+
+        if ($post_data['attribute'] === 'write_offs_position') {
+            if (!isset($answer_query[1])) {
+                return -1;
+            }
+
+            $data = $answer_query[1];
+
+        } else {
+            $data = $chart_data_search->search();
+
+        }
+
+        $keys = array_keys($data_answer['attribute']);
+        $step = 0;
+
+        foreach ($data as $index => $datum) {
+            if ($post_data['attribute'] === 'plan_completed_this_day') {
+                $temp_row['sales_sum'] += $datum['value'];
+                $temp_row['plan'] += $datum['plan'];
+
+            } else if ($post_data['attribute'] === 'plan_completed_this_month') {
+                $temp_row['sales_sum'] += $datum['value'];
+                $temp_row['plan'] += $datum['plan'];
+
+            } else if ($post_data['attribute'] === 'sales') {
+                $data_answer['attribute'][$keys[0]]['data'][] = $datum['value'];
+                $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                $data_answer['attribute'][$keys[1]]['data'][] = $datum['plan'];
+
+            } else if ($post_data['attribute'] === 'count_sales_in_hour') {
+                $data_answer['attribute'][$keys[0]]['data'][] = $datum['value'];
+                $data_answer['attribute'][$keys[1]]['data'][] = $datum['value'] / ($interval_days > 0 ? $interval_days : 1);
+
+            } else if ($post_data['attribute'] === 'avg_sales_value') {
+                if ($step % 2 != 0) {
+                    $step++;
+                    continue;
+                }
+
+                $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                $data_answer['attribute'][$keys[0]]['data'][] = $datum['value'] / ($data[$index + 1]['value'] != 0 ? $data[$index + 1]['value'] : 1);
+                $data_answer['attribute'][$keys[1]]['data'][] = $datum['plan'];
+                $step++;
+
+            } else if ($post_data['attribute'] === 'fot') {
+                if ($step % 2 != 0) {
+                    $step ++;
+                    continue;
+
+                }
+
+                $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                $data_answer['attribute'][$keys[0]]['data'][] = $datum['value'] / (($data[$index + 1]['value'] != 0 ? $data[$index + 1]['value'] : 1) / 100);
+                $data_answer['attribute'][$keys[1]]['data'][] = $datum['plan'];
+                $step++;
+
+            } else if ($post_data['attribute'] === 'sales_sum_on_admin') {
+                if ($step % 2 != 0) {
+                    $step ++;
+                    continue;
+
+                }
+
+                $step++;
+
+                $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                $data_answer['attribute'][$keys[0]]['data'][] = $datum['value'] / ($data[$index + 1]['value'] != 0 ? $data[$index + 1]['value'] : 1);
+
+            } else if ($post_data['attribute'] === 'write_offs') {
+                if ($step % 2 != 0) {
+                    $step++;
+                    continue;
+
+                }
+
+                $step++;
+
+                if (date('d', strtotime($datum['date'])) == 1) {
+                    $temp_row['sales_sum'] = 0;
+                    $temp_row['sum'] = 0;
+                }
+                $temp_row['sales_sum'] += $datum['value'] ?? 0;
+                $temp_row['sum'] += $data[$index + 1]['value'] ?? 0;
+
+                if (strtotime($datum['date']) >= (($post_data['date_start']) ? strtotime($post_data['date_start']) : date('Y-m-d', strtotime('-13 day')))) {
+                    $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                    $data_answer['attribute'][$keys[0]]['data'][] = $data[$index + 1]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[1]]['data'][] = ($data[$index + 1]['value'] ?? 0) / (($datum['value'] != 0 ? $datum['value'] : 1) / 100);
+                    $data_answer['attribute'][$keys[2]]['data'][] = $temp_row['sum'] / ((($temp_row['sales_sum'] != 0) ? $temp_row['sales_sum'] : 1) / 100);
+                }
+            } else if ($post_data['attribute'] === 'user_bonus') {
+                if ($step % 4 == 0) {
+                    $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                    $data_answer['attribute'][$keys[0]]['data'][] = $data[$index]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[1]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[2]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[3]]['data'][] = 0;
+
+                    $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                    $data_answer['attribute'][$keys[0]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[1]]['data'][] = $data[$index + 1]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[2]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[3]]['data'][] = 0;
+
+                    $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                    $data_answer['attribute'][$keys[0]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[1]]['data'][] = 0;
+                    $data_answer['attribute'][$keys[2]]['data'][] = $data[$index + 2]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[3]]['data'][] = $data[$index + 3]['value'] ?? 0;
+
+                }
+
+                $step++;
+
+            } else if ($post_data['attribute'] === 'matrix_sales_sum') {
+                if ($step % 3 == 0) {
+                    $dates[] = $datum['date'] . ' ' . $chart_data_search->day_of_week[date('w', strtotime($datum['date']))];
+                    $data_answer['attribute'][$keys[0]]['data'][] = $data[$index]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[1]]['data'][] = $data[$index + 1]['value'] ?? 0;
+                    $data_answer['attribute'][$keys[2]]['data'][] = $data[$index + 2]['value'] ?? 0;
+
+                }
+
+                $step++;
+            }
+        }
+
+        if ($post_data['attribute'] !== 'count_sales_in_hour') {
+            $chart_opts = [
+                'xaxis' => [
+                    'type' => 'text',
+                    'categories' => $dates,
+                ]
+            ];
+        } else {
+            if ($chart_data_search->mode_shift === 3) {
+                $chart_opts = [
+                    'xaxis' => [
+                        'type' => 'text',
+                        'categories' => array_merge(range(8, 23), range(0, 7))
+                    ]
+                ];
+            } else if ($chart_data_search->mode_shift === 1) {
+                $chart_opts = [
+                    'xaxis' => [
+                        'type' => 'text',
+                        'categories' => range(8, 19)
+                    ]
+                ];
+            } else if ($chart_data_search->mode_shift === 2) {
+                $chart_opts = [
+                    'xaxis' => [
+                        'type' => 'text',
+                        'categories' => array_merge(range(20, 23), range(0, 7))
+                    ]
+                ];
+            } else if ($chart_data_search->mode_shift === 4) {
+                $chart_opts = [
+                    'xaxis' => [
+                        'type' => 'text',
+                        'categories' => range(0, 23)
+                    ]
+                ];
+            }
+
+            $chart_data_search::sortCountSalesInHour($data_answer, $chart_data_search->mode_shift);
+        }
+
+        if ($chart_data_search->mode_level === 2) {
+            $chart_opts['title'] = ['text' => 'Куст ' . $chart_data_search->cluster_id];
+        } else if ($chart_data_search->mode_level === 3) {
+            if ($chart_data_search->attribute_name === 'write_offs_position') {
+                $chart_opts['title'] = ['text' => 'Магазин: ' . $answer_query[0][0]['store_name']];
+            } else {
+                $chart_opts['title'] = ['text' => 'Магазин: ' . $data[0]['store_name']];
+            }
+
+        } else {
+            $chart_opts['title'] = ['text' => 'Розница'];
+        }
+
+        if ($post_data['attribute'] === 'plan_completed_this_day') {
+            $data_answer = [];
+            $data_answer['attribute']['plan_complete_on_this_day'] = round(
+                $temp_row['sales_sum'] /
+                ($temp_row['plan'] !== 0 ? $temp_row['plan'] : 1) *
+                100,
+                2);
+
+        }
+
+        if ($post_data['attribute'] === 'plan_completed_this_month') {
+            $data_answer = [];
+            $data_answer['attribute']['plan_hypothesis_complete_on_this_month'] = round(
+                $temp_row['sales_sum'] /
+                date('d', time()) *
+                date('d', strtotime('last day of this month')) /
+                ($temp_row['plan'] !== 0 ? $temp_row['plan'] : 1) *
+                100,
+                2);
+
+        }
+
+        $answer = ['chart_opts' => $chart_opts, 'data_answer' => $data_answer];
+        return Json::encode($answer);
+    }
+
+    public function actionWriteOffsIndex($date, $cluster_id = null, $store_id = null)
+    {
+        $query_write_offs = WriteOffs::find()
+            ->select([
+                'store_name' => 'city_store.name',
+                'sum' => 'write_offs.summ',
+                'date' => 'write_offs.date',
+                'number' => 'write_offs.number',
+                'comment' => 'write_offs.comment'
+            ])
+            ->innerJoin('export_import_table', 'export_import_table.export_val = write_offs.store_id')
+            ->innerJoin('city_store', 'city_store.id = export_import_table.entity_id')
+            ->innerJoin(
+                'store_dynamic',
+                [
+                    'AND',
+                    'store_dynamic.store_id = city_store.id',
+                    [
+                        '>=',
+                        new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    ],
+                    [
+                        '<',
+                        new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    ]
+                ]
+            )
+            ->andWhere([
+                'export_import_table.entity' => 'city_store'
+            ])
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $cluster_id,
+                'city_store.id' => $store_id
+            ])
+            ->andWhere([
+                'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')' => $date
+            ])
+            ->andWhere([
+                'write_offs.type' => 'Брак'
+            ])
+            ->orderBy([
+                'store_dynamic.value_int' => SORT_ASC,
+                'city_store.id' => SORT_ASC,
+                'write_offs.date' => SORT_ASC,
+            ]);
+
+        $dataProvider = new ArrayDataProvider([
+            'allModels' => $query_write_offs->asArray()->all()
+        ]);
+
+        return $this->render('write-offs', [
+            'dataProvider' => $dataProvider,
+            'date' => $date
+        ]);
+    }
+}
\ No newline at end of file
index 31b7d1af3be79d5d275cbb0d6a39c4eed8f5bae4..a9edbe16f55fcd44d61719ac230ead150f38cc2b 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace app\controllers;
 
+use Yii;
 use yii_app\records\CityStore;
 use yii_app\records\CityStoreSearch;
 use yii\web\Controller;
@@ -40,7 +41,20 @@ class CityStoreController extends Controller
     {
         $searchModel = new CityStoreSearch();
         $dataProvider = $searchModel->search($this->request->queryParams);
-
+        if (Yii::$app->request->isAjax && Yii::$app->request->post('action') == 'saveTg') {
+            $storeId = Yii::$app->request->post('storeId');
+            $tgInput = Yii::$app->request->post('tgInput');
+            if (empty($tgInput)) {
+                return 'not ok';
+            }
+            $cityStore = CityStore::find()->where(['id' => $storeId])->one();
+            if (!$cityStore) {
+                return 'not ok';
+            }
+            $cityStore->tg_chat_id = $tgInput;
+            $cityStore->save(false);
+            return 'ok';
+        }
         return $this->render('/city_store/index', [
             'searchModel' => $searchModel,
             'dataProvider' => $dataProvider,
index 32220d26ed2f38d16eae3e9eb4036f430f265323..db3aa8fd96b02905100f8354a68c48004f9fe0da 100644 (file)
@@ -24,6 +24,7 @@ class InfoTableController extends \yii\web\Controller
             'test' => \yii_app\actions\infoTable\TestAction::class,
             'validate' => \yii_app\actions\dashboard\ValidateAction::class,
             'charts-fot' => \yii_app\actions\infoTable\ChartsFotAction::class,
+            'cabinet' => \yii_app\actions\infoTable\CabinetAction::class,
 
         ];
     }
index 500fbb6603673d3a55034904f7363f85346dd6f2..77735501817bbb294fa1ddbbd6cc6069178b1d01 100644 (file)
@@ -249,7 +249,7 @@ class MatrixErpPropertyController extends Controller
 
 
                             if ($uploadImage) {
-                                if (Images::isImageFile(($uploadImage))) {
+                                if (Images::isImageFile(($uploadImage), ['png', 'jpg'])) {
                                     $image = new Images();
                                     $imageId = $image->loadImage(($uploadImage));
 
index 55701630f26e3674788afb2f509da24723074098..1509a2d060be923842894b1d95f0288424034e32 100755 (executable)
@@ -11,7 +11,6 @@ class PagesController extends \yii\web\Controller
     {
         return [
             'index' => \yii_app\actions\pages\IndexAction::class,
-            'statistics' => \yii_app\actions\pages\StatisticsAction::class,
         ];
     }
 }
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index ad1c3a98e2279dd08f77a38ca01cb8a257a20b69..b58b3b258aa9c3d1214da0b5c57b047c1a7995de 100644 (file)
@@ -5,127 +5,12 @@ namespace app\controllers;
 use GuzzleHttp\Client;
 use Yii;
 use yii\web\Controller;
-use yii\web\Response;
-use yii\filters\VerbFilter;
-use app\models\LoginForm;
-use app\models\ContactForm;
-use yii_app\records\CrmMenu;
-
-class SiteController extends Controller
-{
-    /**
-     * {@inheritdoc}
-     */
-    public function behaviors()
-    {
-        return [
-            'verbs' => [
-                'class' => VerbFilter::class,
-                'actions' => [
-                    'logout' => ['get'],
-                ],
-            ],
-        ];
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function actions()
-    {
-        return [
-            'error' => [
-                'class' => 'yii\web\ErrorAction',
-            ],
-            'captcha' => [
-                'class' => 'yii\captcha\CaptchaAction',
-                'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
-            ],
-        ];
-    }
-
-    /**
-     * Displays homepage.
-     *
-     * @return string
-     */
-    public function actionIndex()
-    {
-        return $this->render('index');
-    }
-
-    /**
-     * Login action.
-     *
-     * @return Response|string
-     */
-    public function actionLogin()
-    {
-        if (!Yii::$app->user->isGuest) {
-            return $this->goHome();
-        }
-
-        $model = new LoginForm();
-        if (Yii::$app->request->isPost) {
-            if ($model->load(Yii::$app->request->post()) && $model->login()) {
-                return $this->goBack();
-            } else {
-                return $this->refresh();
-            }
-        }
-
-        $model->password = '';
-        return $this->renderPartial('login', [
-            'model' => $model,
-        ]);
-    }
-
-    /**
-     * Logout action.
-     *
-     * @return Response
-     */
-    public function actionLogout()
-    {
-        if (!Yii::$app->user->isGuest) {
-            Yii::$app->user->logout();
-        }
-
-        return $this->redirect('/site/login');
-    }
-
-    /**
-     * Displays contact page.
-     *
-     * @return Response|string
-     */
-    public function actionContact()
-    {
-        $model = new ContactForm();
-        if ($model->load(Yii::$app->request->post()) && $model->contact(Yii::$app->params['adminEmail'])) {
-            Yii::$app->session->setFlash('contactFormSubmitted');
-
-            return $this->refresh();
-        }
-        return $this->render('contact', [
-            'model' => $model,
-        ]);
-    }
-
-    /**
-     * Displays about page.
-     *
-     * @return string
-     */
-    public function actionAbout()
-    {
-        return $this->render('about');
-    }
 
+class SiteController extends Controller {
     public function actionMenuTree() {
-//        $client = new Client(['base_uri' => Yii::$app->params['API2_URL']]);
-//        $response = $client->request('GET', '/site/menu-tree?user_id=' . Yii::$app->user->id . '&key=' . Yii::$app->params['API2_TOKEN']);
-//        return $this->asJson(json_decode($response->getBody(), true));
-        return $this->asJson(CrmMenu::getTreeByUserId(Yii::$app->user->id));
+        $client = new Client(['base_uri' => Yii::$app->params['API2_URL']]);
+        $response = $client->request('GET', '/site/menu-tree?user_id=' . Yii::$app->user->id . '&key=' . Yii::$app->params['API2_TOKEN']);
+//        Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
+        return $this->asJson(json_decode($response->getBody(), true));
     }
-}
+}
\ No newline at end of file
index cd30346612530e6d15c16daab117339da4c9d722..2fe3461109384cb29f1122b65e1ac2bf0ad47464 100755 (executable)
@@ -88,7 +88,10 @@ class TabelSearchForm extends Model
                 'group_id' => array_keys(AdminGroup::groupsWithShift())
             ])
             ->andFilterWhere(['group_id' => $this->adminGroupId])
-            ->orderBy(['group_id' => SORT_ASC, 'name' => SORT_ASC])
+            ->orderBy(['IF(group_id IN ('
+                . AdminGroup::GROUP_WORKERS . ', '
+                . AdminGroup::GROUP_WORKERS_ARCHIVE . ', '
+                . AdminGroup::GROUP_FIRED . '),1,0)' => SORT_ASC, 'group_id' => SORT_ASC, 'name' => SORT_ASC])
             ->indexBy('id');
         if ($this->storeId) {
             $adminQuery
index 6064865da3cb1b71917078a5775203b84a3f91cf..c2ecb6ea77131b966d991792d2347c8474c7b5b8 100644 (file)
@@ -16,7 +16,7 @@ class ClientHelper {
         $phone = preg_replace("/[^0-9\,]/i", "", $phone);
         //   $urlstr = preg_replace('/[^A-Za-z0-9_\-]/', '', $urlstr);
         $phone_str = strlen($phone);
-        if ($phone_str == 10) {
+        if ($phone_str == 10 && $phone[0] != '7') {
             $phone = "7$phone";
         } elseif ($phone_str == 11) {
             $str0 = substr($phone, 0, 1);
index 3e353e9c45e81f7c18f424dcfb132e4afbcaeb5c..29499e6c3a59bc4c5b84cc99ee457808f667d663 100644 (file)
@@ -80,4 +80,35 @@ class DataHelper
     {
         return json_decode($string,true,512,JSON_UNESCAPED_UNICODE);
     }
+
+    public static function arraysAreEqual($array1, $array2): bool
+    {
+        array_multisort($array1);
+        array_multisort($array2);
+
+        return ( serialize($array1) === serialize($array2) );
+    }
+
+    public static function mergeArraysByKey($array1, $array2): array
+    {
+        $mergeArray = [];
+        $array1Keys = array_keys($array1);
+        $array2Keys = array_keys($array2);
+        $keys = array_merge($array1Keys,$array2Keys);
+
+        foreach($keys as $key) {
+            $mergeArray[$key] = array_merge_recursive(isset($array1[$key])?$array1[$key]:[],isset($array2[$key])?$array2[$key]:[]);
+        }
+
+        return $mergeArray;
+
+    }
+
+    public static function ruPlural($number, $titles = array(/*1*/'комментарий', /*2*/'комментария', /*5*/'комментариев')): string
+    {
+        $cases = array (2, 0, 1, 1, 1, 2);
+
+        return $number.' '.$titles[($number % 100 > 4 && $number % 100 < 20) ? 2 : $cases[min($number % 10, 5)]];
+    }
+
 }
\ No newline at end of file
index b357f7fe4720cdbc84bfb6efdd38d8daa0c4a800..21252a46a1d4d8ac2c1b7af892652df13297e8d2 100644 (file)
@@ -125,7 +125,7 @@ class File extends FileHelper
         }
 
                self::createDirectory($resizedPath);
-               if (!file_exists($resizedFile)) {
+               if (!file_exists($resizedFile) && !empty($imagePath)) {
                        ImageHelper::resizeImage($imagePath, $resizedFile, $w, $h, $quality);
                }
                return $resizedUrl;
index 2ecd3a82896c6e557caebbdae69ff7b53128aa54..8cb0d7bf71a56a75596eb7d6819c0bff0252025f 100755 (executable)
@@ -2,6 +2,7 @@
 
 namespace yii_app\helpers;
 
+use DateTime;
 use yii\helpers\ArrayHelper;
 use yii_app\records\Admin;
 
@@ -162,4 +163,23 @@ class HtmlHelper
     }
 
 
+    public static function getAdministratorWorkDays($month, $year): int
+    {
+        $adminDayCount = 0;
+        $dayMonthDateRow = $year . '-' . $month . '-01';
+        $dayMonthRow = new DateTime($dayMonthDateRow);
+        $days = date('j', strtotime($dayMonthRow->format('Y-m-t')));
+        foreach (range(1, $days) as $day) {
+            $dayRow = $year . '-' . $month . '-' . $day;
+            $time = new DateTime($dayRow);
+            $dayNumRow = $time->format('w');
+            // считаем дни со вторника по субботу
+            if ($dayNumRow >= 2 && $dayNumRow <= 6) {
+                $adminDayCount++;
+            }
+        }
+        return $adminDayCount;
+    }
+
+
 }
index ac843bdd439de2a062c6b8943352e2ae26808e79..d717223f81c818dde908530e8232cd9b50e7d048 100755 (executable)
@@ -8,6 +8,8 @@ use yii\db\Exception;
 use yii\helpers\ArrayHelper;
 use yii_app\records\Products1c;
 use yii_app\records\Sales;
+use yii_app\records\Timetable;
+use yii_app\services\HolidayService;
 use yii_app\services\SalesService;
 
 class SalaryHelper
@@ -19,6 +21,8 @@ class SalaryHelper
         45=>15,
         40=>15, //Помощник день
         72=>15, //Помощник ночь
+        90=>15, //Помощник ночь
+        -1=>15, //Помощник ночь
     ];
 
     public static function getSqlWhereFromArray($array, $pole)
@@ -107,16 +111,9 @@ class SalaryHelper
         }
 
 
-        if (count($adminGuidArr)) {
-            $i = 0;
-            $where_p = " AND (";
-            foreach ($adminGuidArr as $adminGuid) {
-                if ($i > 0)
-                    $where_p .= " or ";
-                $where_p .= "  sales.seller_id='$adminGuid'";
-                $i++;
-            }
-            $where_p .= " )";
+        if (is_array($adminGuidArr) && count($adminGuidArr)) {
+            $adminGuidArrIn = "'" . implode("', '", $adminGuidArr) . "'";
+            $where_p = " AND sales.seller_id IN ($adminGuidArrIn) ";
         }
 
 
@@ -166,6 +163,8 @@ class SalaryHelper
               
             AND 
                 sales.id = p.check_id 
+            AND 
+                p.type_id = 1
             AND 
                 (p.component_parent_id = '' OR p.component_parent_id = 0 OR p.component_parent_id IS NULL)
             AND
@@ -213,9 +212,9 @@ class SalaryHelper
             $allBonus[$row["seller_id"]]["check"][] = $row;
         }
 
-        foreach ($allBonus as $sallerId => $bonus) {
-            $allBonus2[$sallerId]["bonus"] = round($bonus["bonus"]);
-            $allBonus2[$sallerId]["check"] = $bonus["check"];
+        foreach ($allBonus as $sellerId => $bonus) {
+            $allBonus2[$sellerId]["bonus"] = round($bonus["bonus"]);
+            $allBonus2[$sellerId]["check"] = $bonus["check"];
 
         }
 
@@ -265,17 +264,9 @@ class SalaryHelper
             $whereProducts = 1;
         }
 
-
-        if (count($adminGuidArr)) {
-            $i = 0;
-            $where_p = " AND (";
-            foreach ($adminGuidArr as $adminGuid) {
-                if ($i > 0)
-                    $where_p .= " or ";
-                $where_p .= "  sales.seller_id='$adminGuid'";
-                $i++;
-            }
-            $where_p .= " )";
+        if (is_array($adminGuidArr) && count($adminGuidArr)) {
+            $adminGuidArrIn = "'" . implode("', '", $adminGuidArr) . "'";
+            $where_p = " AND sales.seller_id IN ($adminGuidArrIn) ";
         }
 
 
@@ -446,17 +437,10 @@ class SalaryHelper
 
                     ]
                 );
-                $action2 = $command->getRawSql();
 
                 $data2 = $command->queryAll();
-
-
             }
-
-
-
         } else {
-
             $command = $connection->createCommand("
                 SELECT
                     sales.id,                
@@ -527,7 +511,6 @@ class SalaryHelper
             }
         }
 
-
         return $allBonus2;
     }
 
@@ -584,4 +567,221 @@ class SalaryHelper
 
         return $command->queryColumn();
     }
+
+    public static function getSalariesByFocusGroup(
+        $employeeId,
+        $adminGuid,
+        $arrayProducts,
+        $adminGuidArr,
+        $dateFrom,
+        $dateTo,
+        $exportAdmin,
+        $isAdministrator,
+        $employeeSelectStoreId,
+        $showHolidayVersion = false,
+        $notHolidayCalculate = true
+    ): array {
+        $adminGuidDateArr = [];
+        $adminGuidArrAll = [];
+        if ($showHolidayVersion) {
+            $holidayDatesBetweenPrepared = HolidayService::getHolidayDatesBetween($dateFrom, $dateTo);
+            if ($notHolidayCalculate) {
+                $dataKey = 'notHolidayDatesInterval';
+            } else {
+                $dataKey = 'dayHolidayInArray';
+                $adminGuidDateArr = self::getAdminGuidByStore($dateFrom, $dateTo, $employeeSelectStoreId);
+                $isAdministrator = false;
+            }
+            $dates = ArrayHelper::getValue($holidayDatesBetweenPrepared,  $dataKey);
+        } else {
+            $dates = [
+                0 => [
+                    'dateFrom' => $dateFrom,
+                    'dateTo' => $dateTo,
+                ],
+            ];
+        }
+
+        $arrUsersSalaryServices = [];
+        $arrUsersSalaryRelated = [];
+        $arrUsersSalaryPotted = [];
+        $arrUsersSalaryWrap = [];
+        $arrUsersSalarySalut = [];
+        $arrUsersSalaryOtherItems = [];
+
+        $arrUsersSalary = [
+            "services" => [],
+            "related" => [],
+            "potted" => [],
+            "wrap" => [],
+            "salut" => [],
+            "other_items" => [],
+        ];
+
+        $arrUsersSalaryServicesCheck = [];
+        $arrUsersSalaryRelatedCheck = [];
+        $arrUsersSalaryPottedCheck = [];
+        $arrUsersSalaryWrapCheck = [];
+        $arrUsersSalarySalutCheck = [];
+        $arrUsersSalaryOtherItemsCheck = [];
+
+        foreach ($dates as $key => $datesRow) {
+            $dateFromRow = $datesRow['dateFrom'];
+            $dateToRow = $datesRow['dateTo'];
+            if (
+                false === $notHolidayCalculate
+                &&
+                $dateFromRow == $dateToRow
+                &&
+                !empty($adminGuidDateArr)
+
+            ) {
+                if (array_key_exists($dateFromRow, $adminGuidDateArr)) {
+                    $adminGuidArr = $adminGuidDateArr[$dateFromRow];
+                    $adminGuidArrAll[$dateFromRow] = $adminGuidArr;
+                } else {
+                    continue;
+                }
+            }
+
+            if (!empty($arrayProducts["services"])) {
+                $arrUsersSalaryServicesPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["services"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator);
+                $arrUsersSalaryServices[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalaryServicesPrepared, 'bonus')
+                );
+                $arrUsersSalaryServicesCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalaryServicesCheck,
+                    ArrayHelper::getColumn($arrUsersSalaryServicesPrepared, 'check')
+                );
+            }
+
+            if (!empty($arrayProducts["related"])) {
+                $arrUsersSalaryRelatedPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["related"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator);
+                $arrUsersSalaryRelated[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalaryRelatedPrepared, 'bonus')
+                );
+
+                $arrUsersSalaryRelatedCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalaryRelatedCheck,
+                    ArrayHelper::getColumn($arrUsersSalaryRelatedPrepared, 'check')
+                );
+            }
+
+            if (!empty($arrayProducts["potted"])) {
+                $arrUsersSalaryPottedPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["potted"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator);
+                $arrUsersSalaryPotted[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalaryPottedPrepared, 'bonus')
+                );
+                $arrUsersSalaryPottedCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalaryPottedCheck,
+                    ArrayHelper::getColumn($arrUsersSalaryPottedPrepared, 'check')
+                );
+            }
+
+            if (!empty($arrayProducts["wrap"])) {
+                $arrUsersSalaryWrapPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["wrap"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator);
+                $arrUsersSalaryWrap[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalaryWrapPrepared, 'bonus')
+                );
+                $arrUsersSalaryWrapCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalaryWrapCheck,
+                    ArrayHelper::getColumn($arrUsersSalaryWrapPrepared, 'check')
+                );
+            }
+
+            if (!empty($arrayProducts["other_items"])) {
+                $arrUsersSalaryOtherItemsPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["other_items"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator);
+                $arrUsersSalaryOtherItems[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalaryOtherItemsPrepared, 'bonus')
+                );
+                $arrUsersSalaryOtherItemsCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalaryOtherItemsCheck,
+                    ArrayHelper::getColumn($arrUsersSalaryOtherItemsPrepared, 'check')
+                );
+            }
+
+            if (!empty($arrayProducts["salut"])) {
+                $arrUsersSalarySalutPrepared = SalaryHelper::getSalaryBonusSalut($arrayProducts["salut"], $adminGuidArr, $dateFromRow, $dateToRow, $exportAdmin, $isAdministrator, $employeeSelectStoreId);
+                $arrUsersSalarySalut[] = array_sum(
+                    ArrayHelper::getColumn($arrUsersSalarySalutPrepared, 'bonus')
+                );
+                $arrUsersSalarySalutCheck = DataHelper::mergeArraysByKey(
+                    $arrUsersSalarySalutCheck,
+                    ArrayHelper::getColumn($arrUsersSalarySalutPrepared, 'check')
+                );
+            }
+        }
+
+        $arrUsersSalaryServicesValue = [];
+        if (array_sum($arrUsersSalaryServices) > 0) {
+            $arrUsersSalaryServicesValue = [$adminGuid => array_sum($arrUsersSalaryServices ?? [])];
+        }
+        $arrUsersSalaryRelatedValue = [];
+        if (array_sum($arrUsersSalaryRelated) > 0) {
+            $arrUsersSalaryRelatedValue = [$adminGuid => array_sum($arrUsersSalaryRelated ?? [])];
+        }
+        $arrUsersSalaryPottedValue = [];
+        if (array_sum($arrUsersSalaryPotted) > 0) {
+            $arrUsersSalaryPottedValue = [$adminGuid => array_sum($arrUsersSalaryPotted ?? [])];
+        }
+        $arrUsersSalaryWrapValue = [];
+        if (array_sum($arrUsersSalaryWrap) > 0) {
+            $arrUsersSalaryWrapValue = [$adminGuid => array_sum($arrUsersSalaryWrap ?? [])];
+        }
+        $arrUsersSalarySalutValue = [];
+        if (array_sum($arrUsersSalarySalut) > 0) {
+            $arrUsersSalarySalutValue = [$adminGuid => array_sum($arrUsersSalarySalut ?? [])];
+        }
+        $arrUsersSalaryOtherItemsValue = [];
+        if (array_sum($arrUsersSalaryOtherItems) > 0) {
+            $arrUsersSalaryOtherItemsValue = [$adminGuid => array_sum($arrUsersSalaryOtherItems ?? [])];
+        }
+
+        $arrUsersSalary = [
+            "services" => $arrUsersSalaryServicesValue,
+            "related" => $arrUsersSalaryRelatedValue,
+            "potted" => $arrUsersSalaryPottedValue,
+            "wrap" => $arrUsersSalaryWrapValue,
+            "salut" => $arrUsersSalarySalutValue,
+            "other_items" => $arrUsersSalaryOtherItemsValue,
+        ];
+
+        $arrUsersSalaryCheck = [
+            "services" => self::getSubRows($arrUsersSalaryServicesCheck),
+            "related" => self::getSubRows($arrUsersSalaryRelatedCheck),
+            "potted" => self::getSubRows($arrUsersSalaryPottedCheck),
+            "wrap" => self::getSubRows($arrUsersSalaryWrapCheck),
+            "salut" => self::getSubRows($arrUsersSalarySalutCheck),
+            "other_items" => self::getSubRows($arrUsersSalaryOtherItemsCheck),
+        ];
+
+        return [
+            'arrUsersSalary' => $arrUsersSalary,
+            'arrUsersSalaryCheck' => $arrUsersSalaryCheck,
+            'adminGuidDateArrByFocusGroup' => $adminGuidArrAll,
+        ];
+    }
+
+    public static function getAdminGuidByStore($dateFrom, $dateTo, $employeeSelectStoreId)
+    {
+        $adminsPrepared = Timetable::getAdminsByDates($dateFrom, $dateTo, $employeeSelectStoreId);
+
+        return $adminsPrepared['dateGuids'];
+    }
+
+    public static function getSubRows(array $arrayRows): array
+    {
+        $res = [];
+        if (!empty($arrayRows)) {
+            foreach ($arrayRows as $rows) {
+                if (!empty($rows) && is_array($rows)) {
+                    foreach ($rows as $item) {
+                        $res[] = $item;
+                    }
+                }
+            }
+        }
+
+        return $res;
+    }
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
index 9de516bfc72231b3aeeb46b5a43d48122d99a6ea..85c0c5e99f9ac53366000a6347d1739f0d09ed89 100755 (executable)
@@ -42,7 +42,7 @@ class AdminCheckin extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%admin_checkin}}';
+        return 'admin_checkin';
     }
 
     public function isStart()
index d33372647eeb2259f9261635cf6f94798264361b..3c0a1c02594f778e094fe8520c7954b23a0b8555 100755 (executable)
@@ -32,7 +32,7 @@ class AdminDesktop extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%admin_desktop}}';
+        return 'admin_desktop';
     }
 
     /**
index 73de07e179f18d13083124230d8c26817d85ec43..72048644a8496eab26aec018c645b5b41925e159 100755 (executable)
@@ -27,7 +27,7 @@ class AdminDevice extends ActiveRecord
 {
     public static function tableName()
     {
-        return '{{%admin_device}}';
+        return 'admin_device';
     }
 
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index f8befba498d13f786345896d5280411cb0d2ab82..77e37fe4a2e313dd77ddec7fbd2b4713aea10606 100755 (executable)
@@ -16,6 +16,7 @@ use yii\db\ActiveRecord;
  */
 class AdminGroup extends ActiveRecord
 {
+    const GROUP_FIRED = -1;
     const NOT_INITIALIZED_GROUP = 1000;
 
     const GROUP_HR = 20;
@@ -24,6 +25,7 @@ class AdminGroup extends ActiveRecord
     const GROUP_FLORIST_NIGHT = 35;
     const GROUP_FLORIST_SUPPORT_DAY = 40;
     const GROUP_WORKERS = 45;
+    const GROUP_WORKERS_ARCHIVE = 90;
     const GROUP_ADMINISTRATORS = 50;
     const GROUP_FLORIST_SUPPORT_NIGHT = 72;
     const GROUP_OPERATIONAL_DIRECTOR = 51;
@@ -57,7 +59,7 @@ class AdminGroup extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%admin_group}}';
+        return 'admin_group';
     }
 
     public function rules()
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/erp24/records/AdminPayrollHistory.php b/erp24/records/AdminPayrollHistory.php
new file mode 100644 (file)
index 0000000..88a58b3
--- /dev/null
@@ -0,0 +1,122 @@
+<?php
+
+namespace yii_app\records;
+
+use Yii;
+use yii\helpers\ArrayHelper;
+
+/**
+ * This is the model class for table "admin_payroll_history".
+ *
+ * @property int $id
+ * @property int $admin_id
+ * @property int $store_id
+ * @property int $year
+ * @property int $month
+ * @property int $type_value
+ * @property float $value
+ * @property string $created_at
+ */
+class AdminPayrollHistory extends \yii\db\ActiveRecord
+{
+    const GROUP_VALUE_ALL_TOTAL_PAYROLL = 1;
+    const GROUP_VALUE_TEAM_BONUS_VALUE = 2;
+    const GROUP_VALUE_TEAM_BONUS_DETAIL = 3;
+    const TYPE_VALUE_NUMBER = 'number';
+    const TYPE_VALUE_STRING = 'string';
+
+    /**
+     * {@inheritdoc}
+     */
+    public static function tableName()
+    {
+        return 'admin_payroll_history';
+    }
+
+    public static function setValues(
+        ?array $payrollValues,
+        $employeeId,
+        $storeId,
+        $yearSelect,
+        $monthSelect,
+        $packetNum
+    )
+    {
+        $arrayList = [
+            'allTotalPayroll' => [
+                'value_type' => AdminPayrollHistory::TYPE_VALUE_NUMBER,
+                'group_number' => AdminPayrollHistory::GROUP_VALUE_ALL_TOTAL_PAYROLL,
+            ],
+            'teamBonusValue' => [
+                'value_type' => AdminPayrollHistory::TYPE_VALUE_NUMBER,
+                'group_number' => AdminPayrollHistory::GROUP_VALUE_TEAM_BONUS_VALUE,
+            ],
+            'teamBonusDetail' => [
+                'value_type' => AdminPayrollHistory::TYPE_VALUE_STRING,
+                'group_number' => AdminPayrollHistory::GROUP_VALUE_TEAM_BONUS_DETAIL,
+            ],
+        ];
+
+        foreach ($arrayList as $key => $row) {
+            $groupNumber = ArrayHelper::getValue($row, 'group_number');
+            $typeValue = ArrayHelper::getValue($row, 'value_type');
+            $fieldName = 'value_' . $typeValue;
+            $adminPayrollHistory = new AdminPayrollHistory();
+            $adminPayrollHistory->admin_id = $employeeId;
+            $adminPayrollHistory->store_id = $storeId;
+            $adminPayrollHistory->year = $yearSelect;
+            $adminPayrollHistory->month = $monthSelect;
+            $adminPayrollHistory->$fieldName = $payrollValues[$key];
+            $adminPayrollHistory->group_number = $groupNumber;
+            $adminPayrollHistory->value_type = $typeValue;
+            $adminPayrollHistory->created_at = date('Y-m-d H:i:s');
+            $adminPayrollHistory->created_date = date('Y-m-d');
+            $adminPayrollHistory->packet_num = $packetNum;
+            if ($adminPayrollHistory->validate()) {
+                $adminPayrollHistory->save();
+            } else {
+                if (!empty($adminPayrollHistory->getErrors())) {
+                    $errorString = json_encode($adminPayrollHistory->getErrors(), JSON_UNESCAPED_UNICODE);
+                    $error = 'Error: ' . $errorString . ' >>> ' . __FILE__. ' >>> ' . __LINE__;
+                }
+            }
+        }
+
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rules()
+    {
+        return [
+            [['admin_id', 'store_id', 'year', 'month','packet_num', 'value_type', 'created_at'], 'required'],
+            [['admin_id', 'store_id', 'year', 'month','packet_num', 'group_number'], 'integer'],
+            [['created_at', 'created_date'], 'safe'],
+            [['value_number'], 'number'],
+            [['value_string'], 'safe'],
+            [['value_type'], 'safe'],
+        ];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function attributeLabels()
+    {
+        return [
+            'id' => 'ID',
+            'admin_id' => 'Admin ID',
+            'store_id' => 'Store ID',
+            'year' => 'Year',
+            'month' => 'Month',
+            'group_number' => 'Group Value',
+            'value_number' => 'Value Number',
+            'value_string' => 'Value String',
+            'value_type' => 'Value Type',
+            'created_at' => 'Created At',
+            'created_date' => 'Created Date',
+            'packet_num' => 'packet num',
+        ];
+    }
+}
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 477f3d15f42d798e61ccfe1edc2f12c0231685f9..1cb821ba379d5f6e6c9bb99f6dc68362bb0d97ea 100755 (executable)
@@ -21,6 +21,8 @@ use yii\db\ActiveQueryInterface;
  * @property int|null $shift_correction
  * @property int|null $vacation_day
  * @property string $date_time
+ * @property int|null $part_time_job_hours
+ * @property string $retention_comment
  */
 class AdminPersonBonuses extends \yii\db\ActiveRecord
 {
@@ -48,11 +50,12 @@ class AdminPersonBonuses extends \yii\db\ActiveRecord
                 'prepaid_expense',
                 'counting',
                 'shift_correction',
-                'vacation_day'
+                'vacation_day',
+                'part_time_job_hours'
             ],
                 'integer'
             ],
-            [['date_time'], 'safe'],
+            [['date_time', 'retention_comment'], 'safe'],
             [['date'], 'string', 'max' => 100],
         ];
     }
@@ -71,7 +74,9 @@ class AdminPersonBonuses extends \yii\db\ActiveRecord
             'bonuses' => 'Премия',
             'color_ruble_bonuses' => 'Премия в цвето-рублях',
             'retention' => 'Вычет',
+            'retention_comment' => 'Коментарий к вычету',
             'shift_correction' => 'Коррекция смены',
+            'part_time_job_hours' => 'Подработка в часах',
             'vacation_day' => 'Отпуск, число оплаченных дней',
             'prepaid_expense' => 'Аванс',
             'counting' => 'Подсчёт',
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index aff0ea0..d633003
@@ -487,6 +487,10 @@ class ChartDataSearch
             $plan_query->andWhere([
                 'plan_store.shift_type' => [1, 2]
             ]);
+        } else if ($this->mode_shift === 4) {
+            $rnp_query->andWhere([
+                'rnp_index.shift_type' => 4
+            ]);
         }
 
         if ($this->mode_level === 2) {
@@ -1073,7 +1077,7 @@ class ChartDataSearch
 
     }
 
-    static function CalculationCompanyDataForCharts($date_start, $date_end)
+    static function CalculationCompanyDataForChartsShifts($date_start, $date_end)
     {
 
         $query = StoreDynamic::find();
@@ -1161,7 +1165,40 @@ class ChartDataSearch
 
         //region Проверка на возвраты
         /* Проверка продажи */
-        $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
+        $invalid_sales = Sales::find()->alias('invalid_sales');
+
+        $invalid_sales->innerJoin(
+            'city_store',
+            'city_store.id = invalid_sales.store_id'
+        );
+
+        $invalid_sales->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = invalid_sales.store_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))')
+                ],
+            ]
+        );
+
+        $invalid_sales->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])
+            ->select([
+                'date' => 'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+                'shift_type' => 'if(HOUR(invalid_sales.date) >= 8 && HOUR(invalid_sales.date) < 20, 1, 2)',
+                'cluster_id' => 'store_dynamic.value_int',
+                'store_dynamic_id' => 'store_dynamic.id',
+                'store_id' => 'city_store.id'
+            ]);
+
         $invalid_sales->andWhere([
             '>=',
             'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
@@ -1169,16 +1206,26 @@ class ChartDataSearch
         ]);
 
         $invalid_sales->andWhere([
-            '<=',
+            '<',
             'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
-            date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
+            date('Y-m-d', strtotime($date_end))
         ]);
 
-        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
-        $sales_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
+        $invalid_sales->groupBy([
+            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            'if(HOUR(invalid_sales.date) >= 8 && HOUR(invalid_sales.date) < 20, 1, 2)',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+
+        $invalid_sales->andWhere('invalid_sales.order_id = \'\'');
+
         /* Конец проверки продажи */
         //endregion
 
+        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
+
         //Исключение доставки
         $sales_query->andWhere('sales.order_id = \'\'');
 
@@ -1190,18 +1237,6 @@ class ChartDataSearch
             'city_store.id'
         ]);
         /* Конец продажи */
-
-        /*
-        SELECT SUM(summ)
-        FROM `sales`
-        INNER JOIN city_store ON sales.store_id = city_store.id
-        WHERE (date BETWEEN "2023-08-01 8:00:00" AND "2023-08-02 7:59:59") AND
-            (sales.order_id = "") AND
-            (sales.operation = "Продажа") AND
-            (sales.id NOT IN (
-                SELECT sales.sales_check FROM sales WHERE sales.sales_check != ""
-            ));
-        */
         //endregion
 
         // region ФОТ
@@ -1259,58 +1294,6 @@ class ChartDataSearch
          */
         // endregion
 
-        //region Списания
-        $write_offs_query = WriteOffs::find();
-
-        $write_offs_query->addSelect([
-            'date' => 'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
-            'shift_type' => 'if(HOUR(write_offs.date) >= 8 && HOUR(write_offs.date) < 20, 1, 2)',
-            'cluster_id' => 'store_dynamic.value_int',
-            'store_dynamic_id' => 'store_dynamic.id',
-            'store_id' => 'city_store.id'
-        ]);
-
-        $write_offs_query->innerJoin(
-            'export_import_table',
-            'write_offs.store_id = export_import_table.export_val'
-        );
-
-        $write_offs_query->innerJoin(
-            'city_store',
-            'export_import_table.entity_id = city_store.id'
-        );
-
-        $write_offs_query->innerJoin(
-            'store_dynamic',
-            [
-                'AND',
-                'store_dynamic.store_id = export_import_table.entity_id',
-                [
-                    '<=',
-                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
-                    new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
-                ],
-                [
-                    '>',
-                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
-                    new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
-                ],
-            ]
-        );
-
-        $write_offs_query->andWhere([
-            'write_offs.type' => 'Брак'
-        ]);
-
-        $write_offs_query->addGroupBy([
-            'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
-            'if(HOUR(write_offs.date) >= 8 && HOUR(write_offs.date) < 20, 1, 2)',
-            'store_dynamic.value_int',
-            'store_dynamic.id',
-            'city_store.id'
-        ]);
-        //endregion
-
         //region Ограничения
         //region Даты
 
@@ -1330,14 +1313,6 @@ class ChartDataSearch
             date('Y-m-d', strtotime($date_end))
         ]);
 
-        //Списания
-        $write_offs_query->andWhere([
-            'BETWEEN',
-            'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
-            date('Y-m-d', strtotime($date_start)),
-            date('Y-m-d', strtotime($date_end))
-        ]);
-
         //Основной запрос
         $query->andWhere([
             'BETWEEN',
@@ -1361,11 +1336,6 @@ class ChartDataSearch
             'admin_payroll_days.smena_type' => [1, 2]
         ]);
 
-        //Списания
-        $write_offs_query->andWhere([
-            'if(HOUR(write_offs.date) >= 8 && HOUR(write_offs.date) < 20, 1, 2)' => [1, 2]
-        ]);
-
         //Основной запрос
         $query->andWhere([
             'shift_types.shift_type' => [1, 2]
@@ -1415,15 +1385,30 @@ class ChartDataSearch
             ]
         );
 
+        $query->leftJoin(['invalid_sub_sales' => $invalid_sales],
+            [
+                'AND',
+                'city_store.id = invalid_sub_sales.store_id',
+                'store_dynamic.id = invalid_sub_sales.store_dynamic_id',
+                'dates_column.date = invalid_sub_sales.date',
+                'shift_types.shift_type = invalid_sub_sales.shift_type'
+            ]
+        );
+
 
         $sales_query->addSelect([
             'sales_sum' => 'SUM(sales.summ)',
             'count' => 'COUNT(sales.id)',
         ]);
 
+        $invalid_sales->addSelect([
+            'invalid_sales' => 'SUM(invalid_sales.summ)',
+            'invalid_count' => 'COUNT(invalid_sales.id)',
+        ]);
+
         $query->addSelect([
-            'sales_sum' => 'SUM(sub_sales.sales_sum)',
-            'count_sales' => 'SUM(sub_sales.count)',
+            'sales_sum' => 'SUM(sub_sales.sales_sum) - SUM(if (invalid_sub_sales.invalid_sales IS NOT NULL, invalid_sub_sales.invalid_sales, 0))',
+            'count_sales' => 'SUM(sub_sales.count) - SUM(if (invalid_sub_sales.invalid_count IS NOT NULL, invalid_sub_sales.invalid_count, 0))',
         ]);
 
         $select_array_sales_query = [];
@@ -1464,29 +1449,6 @@ class ChartDataSearch
         ]);
         //endregion
 
-        //region Списания
-        $query->leftJoin(
-            ['sub_write_offs' => $write_offs_query],
-            [
-                'AND',
-                'city_store.id = sub_write_offs.store_id',
-                'store_dynamic.id = sub_write_offs.store_dynamic_id',
-                'dates_column.date = sub_write_offs.date',
-                'shift_types.shift_type = sub_write_offs.shift_type'
-            ]
-        );
-
-
-        $write_offs_query->addSelect([
-            'write_offs' => 'SUM(write_offs.summ)',
-        ]);
-
-        $query->addSelect([
-            'write_offs' => 'SUM(sub_write_offs.write_offs)',
-        ]);
-
-
-        //endregion
         //endregion
 
         $query->orderBy([
@@ -1497,9 +1459,9 @@ class ChartDataSearch
         ]);
 
         //var_dump($plan_store_query->asArray()->all()); exit();
-        //var_dump($write_offs_query->asArray()->all()); exit();
         //var_dump($sales_query->asArray()->all()); exit();
         //var_dump($admin_payroll_days_query->asArray()->all()); exit();
+        //var_dump($invalid_sales->asArray()->all()); exit();
         //var_dump($query->asArray()->all()); exit();
         //var_dump($query->createCommand()->getRawSql()); exit();
 
@@ -1524,6 +1486,9 @@ class ChartDataSearch
 
         $sales_data_batch = $query->asArray()->batch(200);
 
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
         foreach ($sales_data_batch as $sales_data) {
             foreach ($sales_data as $datum) {
 
@@ -1547,34 +1512,35 @@ class ChartDataSearch
                 }
 
                 if ($id != -1) {
-                    $rows = [];
 
                     foreach ($datum as $key => $item) {
                         if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
-                            $rows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
                         }
                     }
+                }
+            }
+        }
 
-                    try {
-                        $transaction = \Yii::$app->db->beginTransaction();
-                        RnpData::deleteAll(['AND', ['index_id' => $id], ['NOT IN', 'alias_id', [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
-                        Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rows)->execute();
-                        $transaction->commit();
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['NOT IN', 'alias_id', [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
 
-                    } catch (\Exception $exception) {
-                        $transaction->rollBack();
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
 
-                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
-                        $message .= $exception->getMessage() . "\n";
-                    }
-                }
-            }
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
         }
 
         return $message;
     }
 
-    static function CalculationCompanyDataUsersBonusForCharts($date_start, $date_end)
+    static function CalculationCompanyDataForChartsDay($date_start, $date_end)
     {
 
         $query = StoreDynamic::find();
@@ -1611,7 +1577,7 @@ class ChartDataSearch
 
         //Генерирует столбец типов смен для каждой даты
         //region Смены
-        $shift_query = (new Query())->from('(SELECT 1 AS shift_type UNION ALL SELECT 2) shift_types')
+        $shift_query = (new Query())->from('(SELECT 4 AS shift_type) shift_types')
             ->select(['shift_type' => 'shift_types.shift_type']);
 
         $query->leftJoin(
@@ -1630,8 +1596,7 @@ class ChartDataSearch
         $sales_query = Sales::find();
 
         $sales_query->addSelect([
-            'date' => 'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
-            'shift_type' => 'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'date' => 'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
             'cluster_id' => 'store_dynamic.value_int',
             'store_dynamic_id' => 'store_dynamic.id',
             'store_id' => 'city_store.id'
@@ -1650,42 +1615,82 @@ class ChartDataSearch
                 [
                     '<=',
                     new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
-                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
                 ],
                 [
                     '>',
                     new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
-                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
                 ],
             ]
         );
 
         //region Проверка на возвраты
         /* Проверка продажи */
-        $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
+        $invalid_sales = Sales::find()->alias('invalid_sales');
+
+        $invalid_sales->innerJoin(
+            'city_store',
+            'city_store.id = invalid_sales.store_id'
+        );
+
+        $invalid_sales->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = invalid_sales.store_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')')
+                ],
+            ]
+        );
+
+        $invalid_sales->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])
+            ->select([
+                'date' => 'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
+                'cluster_id' => 'store_dynamic.value_int',
+                'store_dynamic_id' => 'store_dynamic.id',
+                'store_id' => 'city_store.id'
+            ]);
+
         $invalid_sales->andWhere([
             '>=',
-            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
             date('Y-m-d', strtotime($date_start))
         ]);
 
         $invalid_sales->andWhere([
-            '<=',
-            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
-            date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
+            '<',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
+            date('Y-m-d', strtotime($date_end))
         ]);
 
-        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
-        $sales_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
+        $invalid_sales->groupBy([
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+
+        $invalid_sales->andWhere('invalid_sales.order_id = \'\'');
+
         /* Конец проверки продажи */
         //endregion
 
+        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
+
         //Исключение доставки
         $sales_query->andWhere('sales.order_id = \'\'');
 
         $sales_query->addGroupBy([
-            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
-            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
             'store_dynamic.value_int',
             'store_dynamic.id',
             'city_store.id'
@@ -1693,13 +1698,73 @@ class ChartDataSearch
         /* Конец продажи */
         //endregion
 
+
+        //region Списания
+        $write_offs_query = WriteOffs::find();
+
+        $write_offs_query->addSelect([
+            'date' => 'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
+            'cluster_id' => 'store_dynamic.value_int',
+            'store_dynamic_id' => 'store_dynamic.id',
+            'store_id' => 'city_store.id'
+        ]);
+
+        $write_offs_query->innerJoin(
+            'export_import_table',
+            'write_offs.store_id = export_import_table.export_val'
+        );
+
+        $write_offs_query->innerJoin(
+            'city_store',
+            'export_import_table.entity_id = city_store.id'
+        );
+
+        $write_offs_query->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = export_import_table.entity_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
+                ],
+            ]
+        );
+
+        $write_offs_query->andWhere([
+            'write_offs.type' => 'Брак'
+        ]);
+
+        $write_offs_query->addGroupBy([
+            'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+
+        //endregion
+
         //region Ограничения
         //region Даты
 
         //Продажи
         $sales_query->andWhere([
             'BETWEEN',
-            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+
+        //Списания
+        $write_offs_query->andWhere([
+            'BETWEEN',
+            'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
             date('Y-m-d', strtotime($date_start)),
             date('Y-m-d', strtotime($date_end))
         ]);
@@ -1715,11 +1780,974 @@ class ChartDataSearch
         $query->addGroupBy(['dates_column.date']);
         //endregion
 
-        //region Тип смены
+        $query->addSelect([
+            'shift_type' => 'shift_types.shift_type'
+        ]);
 
-        //Продажи
-        $sales_query->andWhere([
-            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)' => [1, 2]
+        $query->addGroupBy([
+            'shift_types.shift_type'
+        ]);
+
+
+        //region Уровень данных
+
+        $query->addSelect([
+            'cluster_id' => 'store_dynamic.value_int'
+        ]);
+
+        $query->addGroupBy([
+            'store_dynamic.value_int'
+        ]);
+
+        $query->addSelect([
+            'store_id' => 'city_store.id',
+        ]);
+
+        $query->addGroupBy([
+            'city_store.id',
+        ]);
+
+        //endregion
+        //endregion
+
+        //region Атрибут
+
+        //region Продажи
+        $query->leftJoin(
+            ['sub_sales' => $sales_query],
+            [
+                'AND',
+                'city_store.id = sub_sales.store_id',
+                'store_dynamic.id = sub_sales.store_dynamic_id',
+                'dates_column.date = sub_sales.date',
+            ]
+        );
+
+        $query->leftJoin(['invalid_sub_sales' => $invalid_sales],
+            [
+                'AND',
+                'city_store.id = invalid_sub_sales.store_id',
+                'store_dynamic.id = invalid_sub_sales.store_dynamic_id',
+                'dates_column.date = invalid_sub_sales.date',
+            ]
+        );
+
+
+        $sales_query->addSelect([
+            'sales_sum' => 'SUM(sales.summ)',
+            'count' => 'COUNT(sales.id)',
+        ]);
+
+        $invalid_sales->addSelect([
+            'invalid_sales' => 'SUM(invalid_sales.summ)',
+            'invalid_count' => 'COUNT(invalid_sales.id)',
+        ]);
+
+        $query->addSelect([
+            'sales_sum' => 'SUM(sub_sales.sales_sum) - SUM(if (invalid_sub_sales.invalid_sales IS NOT NULL, invalid_sub_sales.invalid_sales, 0))',
+            'count_sales' => 'SUM(sub_sales.count) - SUM(if (invalid_sub_sales.invalid_count IS NOT NULL, invalid_sub_sales.invalid_count, 0))',
+        ]);
+
+        $select_array_sales_query = [];
+        $select_array_query = [];
+        $range = array_merge(range(8, 23), range(0, 7));
+
+        foreach ($range as $item) {
+            $select_array_sales_query['count_sales_in_' . $item . '_hour'] = 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', ' . $item . ', 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', ' . $item . ', 59, 59), \'%H:%i:%s\'), 1, 0))';
+            $select_array_query['count_sales_in_' . $item . '_hour'] = 'SUM(sub_sales.count_sales_in_' . $item . '_hour)';
+        }
+
+        $sales_query->addSelect($select_array_sales_query);
+        $query->addSelect($select_array_query);
+
+        //region Списания
+        $query->leftJoin(
+            ['sub_write_offs' => $write_offs_query],
+            [
+                'AND',
+                'city_store.id = sub_write_offs.store_id',
+                'store_dynamic.id = sub_write_offs.store_dynamic_id',
+                'dates_column.date = sub_write_offs.date',
+            ]
+        );
+
+
+        $write_offs_query->addSelect([
+            'write_offs' => 'SUM(write_offs.summ)',
+        ]);
+
+        $query->addSelect([
+            'write_offs' => 'SUM(sub_write_offs.write_offs)',
+        ]);
+
+
+        //endregion
+        //endregion
+
+        $query->orderBy([
+            'dates_column.date' => SORT_ASC,
+            'store_dynamic.value_int' => SORT_ASC,
+            'city_store.id' => SORT_ASC,
+            'shift_types.shift_type' => SORT_ASC
+        ]);
+
+        //var_dump($plan_store_query->asArray()->all()); exit();
+        //var_dump($write_offs_query->asArray()->all()); exit();
+        //var_dump($sales_query->asArray()->all()); exit();
+        //var_dump($admin_payroll_days_query->asArray()->all()); exit();
+        //var_dump($invalid_sales->asArray()->all()); exit();
+        //var_dump($query->asArray()->all()); exit();
+        //var_dump($query->createCommand()->getRawSql()); exit();
+
+        $message = "";
+
+        $aliases = RnpAlias::find()->select(['id', 'alias'])->asArray()->all();
+
+        $aliases = ArrayHelper::map($aliases, 'alias', 'id');
+
+        $rnp_old_index = RnpIndex::find()->where(['BETWEEN', 'date', $date_start, $date_end])->select([
+            'id',
+            'cluster_id',
+            'store_id',
+            'shift_type',
+            'date',
+        ])->asArray()->all();
+
+        $ids = [];
+        foreach ($rnp_old_index as $index) {
+            $ids[$index['cluster_id'] . $index['store_id'] . $index['shift_type'] . $index['date']] = $index['id'];
+        }
+
+        $sales_data_batch = $query->asArray()->batch(200);
+
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
+        foreach ($sales_data_batch as $sales_data) {
+            foreach ($sales_data as $datum) {
+
+                $id = -1;
+
+                if (array_key_exists($datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date'], $ids)) {
+                    $id = $ids[$datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date']];
+                } else {
+                    $rnp_index = new RnpIndex(['cluster_id' => $datum['cluster_id'], 'store_id' => $datum['store_id'], 'shift_type' => $datum['shift_type'], 'date' => $datum['date']]);
+
+                    if ($rnp_index->save()) {
+                        $id = $rnp_index->id;
+                    } else {
+                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+                        $message .= "Ошибки валидации модели:\n";
+                        foreach ($rnp_index->getErrors() as $error) {
+                            $message .= $error[0] . "\n";
+                        }
+
+                    }
+                }
+
+                if ($id != -1) {
+
+                    foreach ($datum as $key => $item) {
+                        if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
+                        }
+                    }
+                }
+            }
+        }
+
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['NOT IN', 'alias_id', [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
+
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
+        }
+
+        return $message;
+    }
+
+    static function CalculationCompanyDataUsersBonusForChartsShifts($date_start, $date_end)
+    {
+
+        $query = StoreDynamic::find();
+
+        $query->innerJoin('city_store', 'store_dynamic.store_id = city_store.id AND store_dynamic.category = 1');
+
+        // Генерирует столбец дат для каждого магазина в соответствии с кустом
+        //region Даты
+        // Нужно для соединения составляющих запроса (left join)
+        $dates_query = (new Query())->from('(
+                SELECT :date_end - INTERVAL (units.mul + (10 * tens.mul) + (100 * hundreds.mul) + (1000 * thousands.mul)) DAY AS date
+                FROM       (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS units
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS tens
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS hundreds
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS thousands
+        ) a'
+        )->params([':date_end' => date('Y-m-d', strtotime($date_end))])
+            ->andWhere([
+                'BETWEEN', 'a.date', date('Y-m-d', strtotime($date_start)), date('Y-m-d', strtotime($date_end))
+            ]);
+
+        $dates_query->orderBy(['date' => SORT_ASC]);
+
+        $query->leftJoin(
+            ['dates_column' => $dates_query],
+            [
+                'BETWEEN',
+                'dates_column.date',
+                new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+            ]
+        );
+        //endregion
+
+        //Генерирует столбец типов смен для каждой даты
+        //region Смены
+        $shift_query = (new Query())->from('(SELECT 1 AS shift_type UNION ALL SELECT 2) shift_types')
+            ->select(['shift_type' => 'shift_types.shift_type']);
+
+        $query->leftJoin(
+            ['shift_types' => $shift_query],
+            [
+                '=',
+                1,
+                1
+            ]
+        );
+        //endregion
+
+        //region Продажи
+        /* Продажи */
+
+        $sales_query = Sales::find();
+
+        $sales_query->addSelect([
+            'date' => 'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            'shift_type' => 'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'cluster_id' => 'store_dynamic.value_int',
+            'store_dynamic_id' => 'store_dynamic.id',
+            'store_id' => 'city_store.id'
+        ]);
+
+        $sales_query->innerJoin(
+            'city_store',
+            'city_store.id = sales.store_id'
+        );
+
+        $sales_query->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = sales.store_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                ],
+            ]
+        );
+
+        //region Проверка на возвраты
+        /* Проверка продажи */
+        $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
+        $invalid_sales->andWhere([
+            '>=',
+            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            date('Y-m-d', strtotime($date_start))
+        ]);
+
+        $invalid_sales->andWhere([
+            '<=',
+            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
+        ]);
+
+        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
+        $sales_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
+        /* Конец проверки продажи */
+        //endregion
+
+        //Исключение доставки
+        $sales_query->andWhere('sales.order_id = \'\'');
+
+        $sales_query->addGroupBy([
+            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+        /* Конец продажи */
+        //endregion
+
+        //region Ограничения
+        //region Даты
+
+        //Продажи
+        $sales_query->andWhere([
+            'BETWEEN',
+            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+
+        //Основной запрос
+        $query->andWhere([
+            'BETWEEN',
+            'dates_column.date',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+        $query->addSelect(['date' => 'dates_column.date']);
+        $query->addGroupBy(['dates_column.date']);
+        //endregion
+
+        //region Тип смены
+
+        //Продажи
+        $sales_query->andWhere([
+            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)' => [1, 2]
+        ]);
+
+        //Основной запрос
+        $query->andWhere([
+            'shift_types.shift_type' => [1, 2]
+        ]);
+
+        $query->addSelect([
+            'shift_type' => 'shift_types.shift_type'
+        ]);
+
+        $query->addGroupBy([
+            'shift_types.shift_type'
+        ]);
+        //endregion
+
+        //region Уровень данных
+
+        $query->addSelect([
+            'cluster_id' => 'store_dynamic.value_int'
+        ]);
+
+        $query->addGroupBy([
+            'store_dynamic.value_int'
+        ]);
+
+        $query->addSelect([
+            'store_id' => 'city_store.id',
+        ]);
+
+        $query->addGroupBy([
+            'city_store.id',
+        ]);
+
+        //endregion
+        //endregion
+
+        //region Атрибут
+
+        //region Продажи
+        $query->leftJoin(
+            ['sub_sales' => $sales_query],
+            [
+                'AND',
+                'city_store.id = sub_sales.store_id',
+                'store_dynamic.id = sub_sales.store_dynamic_id',
+                'dates_column.date = sub_sales.date',
+                'shift_types.shift_type = sub_sales.shift_type'
+            ]
+        );
+
+        ////region Бонусная
+        $sales_query->leftJoin('users', 'sales.phone = users.phone')
+            ->leftJoin('users_bonus', 'users.id = users_bonus.user_id AND sales.id = users_bonus.check_id AND users_bonus.check_id != \'\'');
+
+        ////endregion
+
+        $sales_query->addSelect([
+            'count_users' => 'SUM( IF (sales.phone IS NOT NULL AND sales.phone != \'\', 1, 0))',
+            'first_minus_user_bonus' => 'SUM( IF (users.first_minus_balance = users_bonus.date, 1, 0))',
+            'second_minus_user_bonus' => 'SUM( IF (users.first_minus_balance < users_bonus.date, 1, 0))'
+        ]);
+
+        $query->addSelect([
+            'count_users' => 'SUM(sub_sales.count_users)',
+            'first_minus_user_bonus' => 'SUM(sub_sales.first_minus_user_bonus)',
+            'second_minus_user_bonus' => 'SUM(sub_sales.second_minus_user_bonus)'
+        ]);
+
+        $query->orderBy([
+            'dates_column.date' => SORT_ASC,
+            'store_dynamic.value_int' => SORT_ASC,
+            'city_store.id' => SORT_ASC,
+            'shift_types.shift_type' => SORT_ASC
+        ]);
+
+        $message = "";
+
+        $aliases = RnpAlias::find()->select(['id', 'alias'])->asArray()->all();
+
+        $aliases = ArrayHelper::map($aliases, 'alias', 'id');
+
+        $rnp_old_index = RnpIndex::find()->where(['BETWEEN', 'date', $date_start, $date_end])->select([
+            'id',
+            'cluster_id',
+            'store_id',
+            'shift_type',
+            'date',
+        ])->asArray()->all();
+
+        $ids = [];
+        foreach ($rnp_old_index as $index) {
+            $ids[$index['cluster_id'] . $index['store_id'] . $index['shift_type'] . $index['date']] = $index['id'];
+        }
+
+        //var_dump($date_start); exit();
+        $sales_data_batch = $query->asArray()->batch(200);
+
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
+        foreach ($sales_data_batch as $sales_data) {
+            foreach ($sales_data as $datum) {
+
+                $id = -1;
+
+                if (array_key_exists($datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date'], $ids)) {
+                    $id = $ids[$datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date']];
+                } else {
+                    $rnp_index = new RnpIndex(['cluster_id' => $datum['cluster_id'], 'store_id' => $datum['store_id'], 'shift_type' => $datum['shift_type'], 'date' => $datum['date']]);
+
+                    if ($rnp_index->save()) {
+                        $id = $rnp_index->id;
+                    } else {
+                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+                        $message .= "Ошибки валидации модели:\n";
+                        foreach ($rnp_index->getErrors() as $error) {
+                            $message .= $error[0] . "\n";
+                        }
+
+                    }
+                }
+
+                if ($id != -1) {
+
+                    foreach ($datum as $key => $item) {
+                        if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
+                        }
+                    }
+                }
+            }
+        }
+
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['alias_id' => [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
+
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
+        }
+
+        return $message;
+    }
+
+    static function CalculationCompanyDataUsersBonusForChartsDay($date_start, $date_end)
+    {
+
+        $query = StoreDynamic::find();
+
+        $query->innerJoin('city_store', 'store_dynamic.store_id = city_store.id AND store_dynamic.category = 1');
+
+        // Генерирует столбец дат для каждого магазина в соответствии с кустом
+        //region Даты
+        // Нужно для соединения составляющих запроса (left join)
+        $dates_query = (new Query())->from('(
+                SELECT :date_end - INTERVAL (units.mul + (10 * tens.mul) + (100 * hundreds.mul) + (1000 * thousands.mul)) DAY AS date
+                FROM       (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS units
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS tens
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS hundreds
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS thousands
+        ) a'
+        )->params([':date_end' => date('Y-m-d', strtotime($date_end))])
+            ->andWhere([
+                'BETWEEN', 'a.date', date('Y-m-d', strtotime($date_start)), date('Y-m-d', strtotime($date_end))
+            ]);
+
+        $dates_query->orderBy(['date' => SORT_ASC]);
+
+        $query->leftJoin(
+            ['dates_column' => $dates_query],
+            [
+                'BETWEEN',
+                'dates_column.date',
+                new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+            ]
+        );
+        //endregion
+
+        //Генерирует столбец типов смен для каждой даты
+        //region Смены
+        $shift_query = (new Query())->from('(SELECT 4 AS shift_type) shift_types')
+            ->select(['shift_type' => 'shift_types.shift_type']);
+
+        $query->leftJoin(
+            ['shift_types' => $shift_query],
+            [
+                '=',
+                1,
+                1
+            ]
+        );
+        //endregion
+
+        //region Продажи
+        /* Продажи */
+
+        $sales_query = Sales::find();
+
+        $sales_query->addSelect([
+            'date' => 'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+            'cluster_id' => 'store_dynamic.value_int',
+            'store_dynamic_id' => 'store_dynamic.id',
+            'store_id' => 'city_store.id'
+        ]);
+
+        $sales_query->innerJoin(
+            'city_store',
+            'city_store.id = sales.store_id'
+        );
+
+        $sales_query->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = sales.store_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
+                ],
+            ]
+        );
+
+        //region Проверка на возвраты
+        /* Проверка продажи */
+        $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
+        $invalid_sales->andWhere([
+            '>=',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
+            date('Y-m-d', strtotime($date_start))
+        ]);
+
+        $invalid_sales->andWhere([
+            '<=',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
+            date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
+        ]);
+
+        $sales_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
+        $sales_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
+        /* Конец проверки продажи */
+        //endregion
+
+        //Исключение доставки
+        $sales_query->andWhere('sales.order_id = \'\'');
+
+        $sales_query->addGroupBy([
+            'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+        /* Конец продажи */
+        //endregion
+
+        //region Ограничения
+        //region Даты
+
+        //Продажи
+        $sales_query->andWhere([
+            'BETWEEN',
+            'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+
+        //Основной запрос
+        $query->andWhere([
+            'BETWEEN',
+            'dates_column.date',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+        $query->addSelect(['date' => 'dates_column.date']);
+        $query->addGroupBy(['dates_column.date']);
+        //endregion
+
+        //Основной запрос
+        $query->addSelect([
+            'shift_type' => 'shift_types.shift_type'
+        ]);
+
+        $query->addGroupBy([
+            'shift_types.shift_type'
+        ]);
+        //endregion
+
+        //region Уровень данных
+
+        $query->addSelect([
+            'cluster_id' => 'store_dynamic.value_int'
+        ]);
+
+        $query->addGroupBy([
+            'store_dynamic.value_int'
+        ]);
+
+        $query->addSelect([
+            'store_id' => 'city_store.id',
+        ]);
+
+        $query->addGroupBy([
+            'city_store.id',
+        ]);
+
+        //endregion
+        //endregion
+
+        //region Атрибут
+
+        //region Продажи
+        $query->leftJoin(
+            ['sub_sales' => $sales_query],
+            [
+                'AND',
+                'city_store.id = sub_sales.store_id',
+                'store_dynamic.id = sub_sales.store_dynamic_id',
+                'dates_column.date = sub_sales.date',
+            ]
+        );
+
+        ////region Бонусная
+        $sales_query->leftJoin('users', 'sales.phone = users.phone')
+            ->leftJoin('users_bonus', 'users.id = users_bonus.user_id AND sales.id = users_bonus.check_id AND users_bonus.check_id != \'\'');
+
+        ////endregion
+
+        $sales_query->addSelect([
+            'count_users' => 'SUM( IF (sales.phone IS NOT NULL AND sales.phone != \'\', 1, 0))',
+            'first_minus_user_bonus' => 'SUM( IF (users.first_minus_balance = users_bonus.date, 1, 0))',
+            'second_minus_user_bonus' => 'SUM( IF (users.first_minus_balance < users_bonus.date, 1, 0))'
+        ]);
+
+        $query->addSelect([
+            'count_users' => 'SUM(sub_sales.count_users)',
+            'first_minus_user_bonus' => 'SUM(sub_sales.first_minus_user_bonus)',
+            'second_minus_user_bonus' => 'SUM(sub_sales.second_minus_user_bonus)'
+        ]);
+
+        $query->orderBy([
+            'dates_column.date' => SORT_ASC,
+            'store_dynamic.value_int' => SORT_ASC,
+            'city_store.id' => SORT_ASC,
+            'shift_types.shift_type' => SORT_ASC
+        ]);
+
+        $message = "";
+
+        $aliases = RnpAlias::find()->select(['id', 'alias'])->asArray()->all();
+
+        $aliases = ArrayHelper::map($aliases, 'alias', 'id');
+
+        $rnp_old_index = RnpIndex::find()->where(['BETWEEN', 'date', $date_start, $date_end])->select([
+            'id',
+            'cluster_id',
+            'store_id',
+            'shift_type',
+            'date',
+        ])->asArray()->all();
+
+        $ids = [];
+        foreach ($rnp_old_index as $index) {
+            $ids[$index['cluster_id'] . $index['store_id'] . $index['shift_type'] . $index['date']] = $index['id'];
+        }
+
+        $sales_data_batch = $query->asArray()->batch(200);
+
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
+        foreach ($sales_data_batch as $sales_data) {
+            foreach ($sales_data as $datum) {
+
+                $id = -1;
+
+                if (array_key_exists($datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date'], $ids)) {
+                    $id = $ids[$datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date']];
+                } else {
+                    $rnp_index = new RnpIndex(['cluster_id' => $datum['cluster_id'], 'store_id' => $datum['store_id'], 'shift_type' => $datum['shift_type'], 'date' => $datum['date']]);
+
+                    if ($rnp_index->save()) {
+                        $id = $rnp_index->id;
+                    } else {
+                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+                        $message .= "Ошибки валидации модели:\n";
+                        foreach ($rnp_index->getErrors() as $error) {
+                            $message .= $error[0] . "\n";
+                        }
+
+                    }
+                }
+
+                if ($id != -1) {
+
+                    foreach ($datum as $key => $item) {
+                        if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
+                        }
+                    }
+                }
+            }
+        }
+
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['alias_id' => [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
+
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
+        }
+
+        return $message;
+    }
+
+    static function CalculationCompanyDataMatrixSalesForChartsShifts($date_start, $date_end)
+    {
+
+        $query = StoreDynamic::find();
+
+        $query->innerJoin('city_store', 'store_dynamic.store_id = city_store.id AND store_dynamic.category = 1');
+
+        // Генерирует столбец дат для каждого магазина в соответствии с кустом
+        //region Даты
+        // Нужно для соединения составляющих запроса (left join)
+        $dates_query = (new Query())->from('(
+                SELECT :date_end - INTERVAL (units.mul + (10 * tens.mul) + (100 * hundreds.mul) + (1000 * thousands.mul)) DAY AS date
+                FROM       (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS units
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS tens
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS hundreds
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS thousands
+        ) a'
+        )->params([':date_end' => date('Y-m-d', strtotime($date_end))])
+            ->andWhere([
+                'BETWEEN', 'a.date', date('Y-m-d', strtotime($date_start)), date('Y-m-d', strtotime($date_end))
+            ]);
+
+        $dates_query->orderBy(['date' => SORT_ASC]);
+
+        $query->leftJoin(
+            ['dates_column' => $dates_query],
+            [
+                'BETWEEN',
+                'dates_column.date',
+                new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+            ]
+        );
+        //endregion
+
+        //Генерирует столбец типов смен для каждой даты
+        //region Смены
+        $shift_query = (new Query())->from('(SELECT 1 AS shift_type UNION ALL SELECT 2) shift_types')
+            ->select(['shift_type' => 'shift_types.shift_type']);
+
+        $query->leftJoin(
+            ['shift_types' => $shift_query],
+            [
+                '=',
+                1,
+                1
+            ]
+        );
+        //endregion
+
+        //region Матрица
+        $matrix_query = Sales::find();
+
+        $matrix_query->addSelect([
+            'date' => 'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            'shift_type' => 'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'cluster_id' => 'store_dynamic.value_int',
+            'store_dynamic_id' => 'store_dynamic.id',
+            'store_id' => 'city_store.id'
+        ]);
+
+        $matrix_query->innerJoin(
+            'city_store',
+            'city_store.id = sales.store_id'
+        );
+
+        $matrix_query->innerJoin(
+            'store_dynamic',
+            [
+                'AND',
+                'store_dynamic.store_id = sales.store_id',
+                [
+                    '<=',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                ],
+                [
+                    '>',
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                ],
+            ]
+        );
+
+        //region Проверка на возвраты
+        /* Проверка продажи */
+        $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
+        $invalid_sales->andWhere([
+            '>=',
+            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            date('Y-m-d', strtotime($date_start))
+        ]);
+
+        $invalid_sales->andWhere([
+            '<=',
+            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
+        ]);
+        /* Конец проверки продажи */
+        //endregion
+
+        //Исключение доставки
+        $matrix_query->andWhere('sales.order_id = \'\'');
+        /* Конец продажи */
+
+        $matrix_query->andWhere(['sales.operation' => Sales::OPERATION_SALE]);
+        $matrix_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
+
+        $matrix_query->addGroupBy([
+            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'store_dynamic.value_int',
+            'store_dynamic.id',
+            'city_store.id'
+        ]);
+
+        $matrix_query->andWhere([
+            'AND',
+            [
+                '>=',
+                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                date('Y-m-d', strtotime($date_start))
+            ],
+            [
+                '<=',
+                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                date('Y-m-d', strtotime($date_end))
+            ]
+        ]);
+
+        $matrix_query->innerJoin('sales_products', 'sales.id = sales_products.check_id')
+            ->innerJoin('products_1c', 'sales_products.product_id = products_1c.id')
+            ->innerJoin('products_class', 'products_1c.parent_id = products_class.category_id AND products_class.tip = \'matrix\'');
+
+        $matrix_season_guid = Products1c::find()->where(['LIKE', 'name', 'Сезонная матрица'])->select(['id'])->column()[0] ?? '';
+        $matrix_base_guid = Products1c::find()->where(['LIKE', 'name', 'Матрица базовая'])->select(['id'])->column()[0] ?? '';
+        $matrix_new_guid = Products1c::find()->where(['LIKE', 'name', 'Новая матрица'])->select(['id'])->column()[0] ?? '';
+
+        $matrix_group = Products1c::find()
+            ->andWhere(
+                ['IN',
+                    'products_1c.parent_id',
+                    [
+                        $matrix_season_guid, // Сезонная
+                        $matrix_base_guid, // Базовая
+                        $matrix_new_guid, // Новая
+                    ],
+                ]
+            )
+            ->select([
+                'id' => 'products_1c.id',
+                'parent_id' => 'products_1c.parent_id'
+            ]);
+
+        $matrix_query->leftJoin(['matrix_group' => $matrix_group], '(products_1c.id = matrix_group.id OR products_1c.parent_id = matrix_group.id)')
+            ->addSelect([
+                'matrix_base_summ' => 'SUM(if (matrix_group.parent_id = \'' . $matrix_base_guid . '\' OR matrix_group.id = \'' . $matrix_base_guid . '\', sales_products.summ, 0))', // Базовая
+                'matrix_season_summ' => 'SUM(if (matrix_group.parent_id = \'' . $matrix_season_guid . '\' OR matrix_group.id = \'' . $matrix_season_guid . '\', sales_products.summ, 0))', // Сезонная
+                'matrix_new_summ' => 'SUM(if (matrix_group.parent_id = \'' . $matrix_new_guid . '\' OR matrix_group.id = \'' . $matrix_new_guid . '\', sales_products.summ, 0))' // Новая
+            ]);
+
+        $query->leftJoin(
+            ['matrix' => $matrix_query],
+            [
+                'AND',
+                'city_store.id = matrix.store_id',
+                'store_dynamic.id = matrix.store_dynamic_id',
+                'dates_column.date = matrix.date',
+                'shift_types.shift_type = matrix.shift_type'
+            ]
+        );
+        // endregion
+
+        //region Ограничения
+        //region Даты
+
+        //Основной запрос
+        $query->andWhere([
+            'BETWEEN',
+            'dates_column.date',
+            date('Y-m-d', strtotime($date_start)),
+            date('Y-m-d', strtotime($date_end))
+        ]);
+
+        $query->addSelect(['date' => 'dates_column.date']);
+        $query->addGroupBy(['dates_column.date']);
+        //endregion
+
+        //region Тип смены
+
+        //Продажи
+        $matrix_query->andWhere([
+            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)' => [1, 2]
         ]);
 
         //Основной запрос
@@ -1757,38 +2785,15 @@ class ChartDataSearch
         //endregion
         //endregion
 
-        //region Атрибут
-
-        //region Продажи
-        $query->leftJoin(
-            ['sub_sales' => $sales_query],
-            [
-                'AND',
-                'city_store.id = sub_sales.store_id',
-                'store_dynamic.id = sub_sales.store_dynamic_id',
-                'dates_column.date = sub_sales.date',
-                'shift_types.shift_type = sub_sales.shift_type'
-            ]
-        );
-
-        ////region Бонусная
-        $sales_query->leftJoin('users', 'sales.phone = users.phone')
-            ->leftJoin('users_bonus', 'users.id = users_bonus.user_id AND sales.id = users_bonus.check_id AND users_bonus.check_id != \'\'');
-
-        ////endregion
-
-        $sales_query->addSelect([
-            'count_users' => 'SUM( IF (sales.phone IS NOT NULL AND sales.phone != \'\', 1, 0))',
-            'first_minus_user_bonus' => 'SUM( IF (users.first_minus_balance = users_bonus.date, 1, 0))',
-            'second_minus_user_bonus' => 'SUM( IF (users.first_minus_balance < users_bonus.date, 1, 0))'
-        ]);
-
         $query->addSelect([
-            'count_users' => 'SUM(sub_sales.count_users)',
-            'first_minus_user_bonus' => 'SUM(sub_sales.first_minus_user_bonus)',
-            'second_minus_user_bonus' => 'SUM(sub_sales.second_minus_user_bonus)'
+            'matrix_base_summ' => 'SUM(matrix.matrix_base_summ)',
+            'matrix_season_summ' => 'SUM(matrix.matrix_season_summ)',
+            'matrix_new_summ' => 'SUM(matrix.matrix_new_summ)',
         ]);
 
+
+        //endregion
+
         $query->orderBy([
             'dates_column.date' => SORT_ASC,
             'store_dynamic.value_int' => SORT_ASC,
@@ -1817,6 +2822,9 @@ class ChartDataSearch
 
         $sales_data_batch = $query->asArray()->batch(200);
 
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
         foreach ($sales_data_batch as $sales_data) {
             foreach ($sales_data as $datum) {
 
@@ -1840,34 +2848,35 @@ class ChartDataSearch
                 }
 
                 if ($id != -1) {
-                    $rows = [];
 
                     foreach ($datum as $key => $item) {
                         if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
-                            $rows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
                         }
                     }
+                }
+            }
+        }
 
-                    try {
-                        $transaction = \Yii::$app->db->beginTransaction();
-                        RnpData::deleteAll(['AND', ['index_id' => $id], ['alias_id' => [RnpAlias::USERS_COUNT_ID, RnpAlias::FIRST_MINUS_USER_BONUS_ID, RnpAlias::SECOND_MINUS_USER_BONUS_ID]]]);
-                        Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rows)->execute();
-                        $transaction->commit();
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['alias_id' => [RnpAlias::MATRIX_NEW_SUMM_ID, RnpAlias::MATRIX_SEASON_SUMM_ID, RnpAlias::MATRIX_BASE_SUMM_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
 
-                    } catch (\Exception $exception) {
-                        $transaction->rollBack();
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
 
-                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
-                        $message .= $exception->getMessage() . "\n";
-                    }
-                }
-            }
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
         }
 
         return $message;
     }
 
-    static function CalculationCompanyDataMatrixSalesForCharts($date_start, $date_end)
+    static function CalculationCompanyDataMatrixSalesForChartsDay($date_start, $date_end)
     {
 
         $query = StoreDynamic::find();
@@ -1904,7 +2913,7 @@ class ChartDataSearch
 
         //Генерирует столбец типов смен для каждой даты
         //region Смены
-        $shift_query = (new Query())->from('(SELECT 1 AS shift_type UNION ALL SELECT 2) shift_types')
+        $shift_query = (new Query())->from('(SELECT 4 AS shift_type) shift_types')
             ->select(['shift_type' => 'shift_types.shift_type']);
 
         $query->leftJoin(
@@ -1921,8 +2930,7 @@ class ChartDataSearch
         $matrix_query = Sales::find();
 
         $matrix_query->addSelect([
-            'date' => 'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
-            'shift_type' => 'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'date' => 'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
             'cluster_id' => 'store_dynamic.value_int',
             'store_dynamic_id' => 'store_dynamic.id',
             'store_id' => 'city_store.id'
@@ -1941,12 +2949,12 @@ class ChartDataSearch
                 [
                     '<=',
                     new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
-                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
                 ],
                 [
                     '>',
                     new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
-                    new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
                 ],
             ]
         );
@@ -1956,13 +2964,13 @@ class ChartDataSearch
         $invalid_sales = Sales::find()->alias('invalid_sales')->andWhere(['invalid_sales.operation' => Sales::OPERATION_RETURN])->select(['check_id' => 'invalid_sales.sales_check']);
         $invalid_sales->andWhere([
             '>=',
-            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
             date('Y-m-d', strtotime($date_start))
         ]);
 
         $invalid_sales->andWhere([
             '<=',
-            'if (HOUR(invalid_sales.date) < 8, DATE_FORMAT(DATE_SUB(invalid_sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\'))',
+            'DATE_FORMAT(invalid_sales.date, \'%Y-%m-%d\')',
             date('Y-m-d', strtotime('+1 week', strtotime($date_start)))
         ]);
         /* Конец проверки продажи */
@@ -1976,8 +2984,7 @@ class ChartDataSearch
         $matrix_query->andWhere(['NOT IN', 'sales.id', $invalid_sales]);
 
         $matrix_query->addGroupBy([
-            'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
-            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+            'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
             'store_dynamic.value_int',
             'store_dynamic.id',
             'city_store.id'
@@ -1987,12 +2994,12 @@ class ChartDataSearch
             'AND',
             [
                 '>=',
-                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
                 date('Y-m-d', strtotime($date_start))
             ],
             [
                 '<=',
-                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
                 date('Y-m-d', strtotime($date_end))
             ]
         ]);
@@ -2035,7 +3042,6 @@ class ChartDataSearch
                 'city_store.id = matrix.store_id',
                 'store_dynamic.id = matrix.store_dynamic_id',
                 'dates_column.date = matrix.date',
-                'shift_types.shift_type = matrix.shift_type'
             ]
         );
         // endregion
@@ -2057,16 +3063,7 @@ class ChartDataSearch
 
         //region Тип смены
 
-        //Продажи
-        $matrix_query->andWhere([
-            'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)' => [1, 2]
-        ]);
-
         //Основной запрос
-        $query->andWhere([
-            'shift_types.shift_type' => [1, 2]
-        ]);
-
         $query->addSelect([
             'shift_type' => 'shift_types.shift_type'
         ]);
@@ -2134,6 +3131,9 @@ class ChartDataSearch
 
         $sales_data_batch = $query->asArray()->batch(200);
 
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+
         foreach ($sales_data_batch as $sales_data) {
             foreach ($sales_data as $datum) {
 
@@ -2157,28 +3157,29 @@ class ChartDataSearch
                 }
 
                 if ($id != -1) {
-                    $rows = [];
 
                     foreach ($datum as $key => $item) {
                         if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type'])) {
-                            $rows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
                         }
                     }
+                }
+            }
+        }
 
-                    try {
-                        $transaction = \Yii::$app->db->beginTransaction();
-                        RnpData::deleteAll(['AND', ['index_id' => $id], ['IN', 'alias_id', [RnpAlias::MATRIX_NEW_SUMM_ID, RnpAlias::MATRIX_SEASON_SUMM_ID, RnpAlias::MATRIX_BASE_SUMM_ID]]]);
-                        Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rows)->execute();
-                        $transaction->commit();
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(['AND', ['index_id' => $rnpIndexId], ['alias_id' => [RnpAlias::MATRIX_NEW_SUMM_ID, RnpAlias::MATRIX_SEASON_SUMM_ID, RnpAlias::MATRIX_BASE_SUMM_ID]]]);
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+            $message .= "COUNT(RnpRows) = " . count($rnpDataRows);
 
-                    } catch (\Exception $exception) {
-                        $transaction->rollBack();
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
 
-                        $message .= "ЗАПИСЬ store_id = " . $datum['store_id'] . " ОТ: " . $datum['date'] . " АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
-                        $message .= $exception->getMessage() . "\n";
-                    }
-                }
-            }
+            $message .= "АТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
         }
 
         return $message;
@@ -2195,10 +3196,11 @@ class ChartDataSearch
             $data['attribute']['count_sales_in_hour']['data'] = array_merge(array_slice($data['attribute']['count_sales_in_hour']['data'], 20, 4), array_slice($data['attribute']['count_sales_in_hour']['data'], 0, 8));
             $data['attribute']['avg_count_sales_in_hour']['data'] = array_merge(array_slice($data['attribute']['avg_count_sales_in_hour']['data'], 20, 4), array_slice($data['attribute']['avg_count_sales_in_hour']['data'], 0, 8));
 
-        } else {
+        } else if ($shift_type === 3) {
             $data['attribute']['count_sales_in_hour']['data'] = array_merge(array_slice($data['attribute']['count_sales_in_hour']['data'], 8, 12), array_slice($data['attribute']['count_sales_in_hour']['data'], 20, 4), array_slice($data['attribute']['count_sales_in_hour']['data'], 0, 8));
             $data['attribute']['avg_count_sales_in_hour']['data'] = array_merge(array_slice($data['attribute']['avg_count_sales_in_hour']['data'], 8, 12), array_slice($data['attribute']['avg_count_sales_in_hour']['data'], 20, 4), array_slice($data['attribute']['avg_count_sales_in_hour']['data'], 0, 8));
 
         }
+
     }
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index f3bd301faba06be4caa87a9faec3d025a4b612ad..68e03924f92251b935cc10d9593c02c02d5094b5 100755 (executable)
@@ -17,7 +17,7 @@ class CrmMenu extends ActiveRecord
 {
     public static function tableName()
     {
-        return '{{%crm_menu}}';
+        return 'crm_menu';
     }
 
     /** Свёрнуто ли меню для данной страницы */
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index f23878a..11dbe4f
@@ -19,6 +19,7 @@ use Yii;
  * @property int $created_by Кто создал, ID из Admin
  * @property string $store_id GUID магазина
  * @property int $price Ставка в рублях за час
+ * @property int $salary_shift Ставка в рублях за смену
  * @property int $status 0 - в ожидании, 1 - подтверждено, 2 - отказано
  * @property int $status_source -1 - получена ошибка в системе, 0 - не создано, 1 - создано в 1С
  */
@@ -50,6 +51,7 @@ class EmployeeOnShift extends \yii\db\ActiveRecord
             [['guid', 'phone', 'created_at', 'shift_date', 'shift_type', 'datetime_start', 'datetime_end', 'created_by', 'store_id', 'price'], 'required'],
             [['created_at', 'shift_date', 'datetime_start', 'datetime_end'], 'safe'],
             [['shift_type', 'created_by', 'price', 'status', 'status_source'], 'integer'],
+            [['salary_shift'], 'in', 'range' => Timetable::getSalariesDay(), 'skipOnEmpty' => false],
             [['guid', 'store_id'], 'string', 'max' => 36],
             [['phone'], 'string', 'max' => 16],
             [['first_name', 'last_name'], 'string', 'max' => 40],
@@ -75,6 +77,7 @@ class EmployeeOnShift extends \yii\db\ActiveRecord
             'created_by' => 'Created By',
             'store_id' => 'Store ID',
             'price' => 'Price',
+            'salary_shift' => 'Salary Shift',
             'status' => 'Status',
             'status_source' => 'status_source',
         ];
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 811dc4b5a036598351569b3b2844275994349c03..e6d28b7031e3402dc8b9cae631a9897fb6389609 100755 (executable)
@@ -25,7 +25,7 @@ class ErrorLog extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%error_log}}';
+        return 'error_log';
     }
 
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 3a816b3a8ba4a23ad60d6069da2cd8efecd198a9..e61a3ec2c543cb1fe0b94fb5c8f78abb466b20a4 100755 (executable)
@@ -20,7 +20,7 @@ class Holiday extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%holiday}}';
+        return 'holiday';
     }
 
     public function attributeLabels()
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 52baffa..fe07bb9
@@ -112,15 +112,23 @@ class Images extends \yii\db\ActiveRecord
         return false;
     }
 
-    public static function isImageFile($file)
+    public static function isImageFile($file, $extension = null)
     {
         $result = false;
 
         if(!empty($file)) {
             $ar_file_name = explode('/', $file->type);
-            $type = ($ar_file_name[array_key_first($ar_file_name)]);
+            $type = array_shift($ar_file_name);
+
             if ($type === 'image') {
-                $result = true;
+                if (!empty($extension) && is_array($extension)) {
+                    $extensionFile = array_shift($ar_file_name);
+                    if (in_array($extensionFile, $extension)) {
+                        $result = true;
+                    }
+                } else {
+                    $result = true;
+                }
             }
         }
 
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 0e844fd..87379f4
@@ -40,7 +40,12 @@ class MatrixErpProperty extends \yii\db\ActiveRecord
             [['description'], 'string'],
             [['id'], 'integer'],
             [['image_id', 'created_admin_id', 'updated_admin_id'], 'integer'],
-            [['imageFile'], 'file', 'extensions' => 'png, jpg',],
+            [
+                [
+                    'imageFile'
+                ],
+                'file', 'skipOnEmpty' => true, 'extensions' => 'png, jpg', 'checkExtensionByMimeType' => false
+            ],
             [['mediaFile'], 'safe'],
             [['guid', 'date', 'created_at', 'updated_at'], 'string', 'max' => 100],
             [['url_link_video'], 'string', 'max' => 255],
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/erp24/records/NotifiableUser.php b/erp24/records/NotifiableUser.php
new file mode 100644 (file)
index 0000000..2ba1dd6
--- /dev/null
@@ -0,0 +1,53 @@
+<?php
+
+namespace yii_app\records;
+
+use Yii;
+
+/**
+ * This is the model class for table "notifiable_user".
+ *
+ * @property int $id
+ * @property string $phone Номер телефона
+ * @property string $type Тип сообщения
+ * @property string $data Дополнительная информация, например, в виде json-объекта
+ * @property int $status Вспомогательная переменная для маркировки записей перед удалением во время копирования
+ */
+class NotifiableUser extends \yii\db\ActiveRecord
+{
+    /**
+     * {@inheritdoc}
+     */
+    public static function tableName()
+    {
+        return 'notifiable_user';
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function rules()
+    {
+        return [
+            [['phone', 'type', 'data'], 'required'],
+            [['data'], 'string'],
+            [['status'], 'integer'],
+            [['phone'], 'string', 'max' => 16],
+            [['type'], 'string', 'max' => 255],
+        ];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function attributeLabels()
+    {
+        return [
+            'id' => 'ID',
+            'phone' => 'Phone',
+            'type' => 'Type',
+            'data' => 'Data',
+            'status' => 'Status',
+        ];
+    }
+}
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 922f30f..e570d3c
@@ -134,12 +134,6 @@ use Yii;
  * @property int $1c_send Отправлено в 1c
  * @property string $check_id_arr
  * @property string $data_md5
- *
- * @property Sales $sales
- * @property CityStore $storeObj
- * @property Admin $courierObj
- * @property Admin $floristObj
- * @property OrdersStatus $status
  */
 class OrdersAmo extends \yii\db\ActiveRecord
 {
@@ -315,32 +309,4 @@ class OrdersAmo extends \yii\db\ActiveRecord
             'data_md5' => 'Data Md5',
         ];
     }
-
-    public function getSales()
-    {
-        return $this->hasMany(Sales::class, ['order_id' => 'id'])
-            ->orderBy([
-                'date' => SORT_ASC
-            ]);
-    }
-
-    public function getStoreObj()
-    {
-        return $this->hasOne(CityStore::class, ['id' => 'store_id']);
-    }
-
-    public function getFloristObj()
-    {
-        return $this->hasOne(Admin::class, ['id' => 'florist_id']);
-    }
-
-    public function getCourierObj()
-    {
-        return $this->hasOne(Admin::class, ['id' => 'courier_id']);
-    }
-
-    public function getStatus()
-    {
-        return $this->hasOne(OrdersStatus::class, ['status_id' => 'status_id']);
-    }
 }
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index e18ab7c0d12e99ce29b2389620f6f6a49603e7ca..030328e625fed49c29356ff8cde1748739f8dd6f 100755 (executable)
@@ -11,14 +11,24 @@ use yii_app\records\SchedulerTaskLog;
  */
 class SchedulerTaskLogSearch extends SchedulerTaskLog
 {
+
+    public $status;
+
+    public $statusArray = [
+        -1 => 'Пропущено',
+        0 => 'Все',
+        1 => 'Выполнено'
+    ];
+
     /**
      * {@inheritdoc}
      */
     public function rules()
     {
         return [
-            [['id', 'task_num'], 'integer'],
+            [['id', 'task_num', 'status'], 'integer'],
             [['date_start', 'date_stop', 'name', 'alias', 'description', 'result', 'error', 'log', 'date'], 'safe'],
+            ['status', 'default', 'value' => 0]
         ];
     }
 
@@ -72,6 +82,22 @@ class SchedulerTaskLogSearch extends SchedulerTaskLog
             ->andFilterWhere(['like', 'log', $this->log])
             ->andFilterWhere(['like', 'date', $this->date]);
 
+        if ($this->status == -1) {
+            $query->andWhere([
+                'AND',
+                'date_start IS NULL',
+                'date_stop IS NULL',
+            ]);
+
+        } else if ($this->status == 1) {
+            $query->andWhere([
+                'AND',
+                'date_start IS NOT NULL',
+                'date_stop IS NOT NULL'
+            ]);
+
+        }
+
         return $dataProvider;
     }
 }
old mode 100755 (executable)
new mode 100644 (file)
index d628d3318601ec0dbd43d8f4e27159971c16d261..e420a04ea5adfc3a0eb32cf520ccdc3dc7746352 100755 (executable)
@@ -26,7 +26,7 @@ class Shift extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%timetable_shift}}';
+        return 'timetable_shift';
     }
 
     public function rules()
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 746f90d..17c996f
@@ -16,7 +16,7 @@ use Yii;
  * @property string $division_date дата деления
  * @property int $division_hours
  * @property string $delivery_date_fact Дата прихода товара на склад 
- * @ property int $price_logistic
+ * @property int $price_logistic
  * @property string $comments
  * @property int $admin_id
  * @property string $date_add
@@ -25,12 +25,9 @@ use Yii;
  * @property string $status_logi
  * @property string $date_update Дата и врепмя обновления информации в таблице храннеия data
  * @property string $update_html HTML блок расчета по формулам
- * @property int city_id
  */
 class StoreOrders extends \yii\db\ActiveRecord
 {
-    public $providers;
-
     /**
      * {@inheritdoc}
      */
@@ -45,9 +42,9 @@ class StoreOrders extends \yii\db\ActiveRecord
     public function rules()
     {
         return [
-            [['name', 'parent_id', 'date_start', 'date_end', 'delivery_date', 'division_date', 'division_hours', 'delivery_date_fact', /*'price_logistic',*/ 'comments', 'admin_id', 'date_add', 'providers_arr', 'status_logi', 'date_update', 'update_html'], 'required'],
-            [['parent_id', 'division_hours', /*'price_logistic',*/ 'admin_id', 'status'], 'integer'],
-            [['date_start', 'date_end', 'delivery_date', 'division_date', 'delivery_date_fact', 'date_add', 'date_update', 'city_id', 'providers'], 'safe'],
+            [['name', 'parent_id', 'date_start', 'date_end', 'delivery_date', 'division_date', 'division_hours', 'delivery_date_fact', 'price_logistic', 'comments', 'admin_id', 'date_add', 'providers_arr', 'status_logi', 'date_update', 'update_html'], 'required'],
+            [['parent_id', 'division_hours', 'price_logistic', 'admin_id', 'status'], 'integer'],
+            [['date_start', 'date_end', 'delivery_date', 'division_date', 'delivery_date_fact', 'date_add', 'date_update'], 'safe'],
             [['comments', 'status_logi', 'update_html'], 'string'],
             [['name', 'providers_arr'], 'string', 'max' => 255],
         ];
@@ -79,16 +76,4 @@ class StoreOrders extends \yii\db\ActiveRecord
             'update_html' => 'Update Html',
         ];
     }
-
-    public function getCity() {
-        return $this->hasOne(CityStore::class, ['id' => 'city_id']);
-    }
-
-    public function getProviders() {
-        return explode(',', $this->providers_arr);
-    }
-
-    public function setProviders() {
-        $this->providers_arr = implode(',', $this->providers);
-    }
 }
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index 2e43d28a1912abb6cccc4c46a2866aeee14d1d32..7901d5de0205d88eb3fe2fb14dc6ae02b920160d 100755 (executable)
@@ -5,6 +5,7 @@ namespace yii_app\records;
 
 use yii\db\ActiveQuery;
 use yii\db\ActiveRecord;
+use yii\helpers\ArrayHelper;
 
 /**
  * Табель сотрудников
@@ -21,6 +22,7 @@ use yii\db\ActiveRecord;
  * @property string $time_end
  * @property float $work_time
  * @ property float $price_hour
+ * @property int $salary_shift
  * @property int $slot_type_id
  * @property string $comment
  * @property int $date_add
@@ -63,7 +65,64 @@ class Timetable extends ActiveRecord
 
     public static function tableName()
     {
-        return '{{%timetable}}';
+        return 'timetable';
+    }
+
+    public static function getSalariesDay() {
+        return [900, 1200, 1500, 1700, 1800, 2000, 2500, 3500, 5000];
+    }
+
+    public function getSalaryShift($timetableId) : array
+    {
+
+        $salesByAdminPrepared = $this->salesService->getSalesByAdmin($adminGuid, $dateFrom, $dateTo, $isAdministrator);
+
+        $timeTable = [];
+        if (in_array($adminGuid, $this->adminAdministratorGuids)) {
+            if (!empty($this->timeTable)) {
+                $timeTable = $this->timeTable;
+            }
+        }
+
+        $result = $this->salesService->getSaleSumByDateArray($salesByAdminPrepared, $timeTable);
+
+        return $result;
+
+    }
+
+    public static function getAllowEditShift($slotDate, $days = 5) : bool
+    {
+        return (
+            date('Y-m-d',strtotime($slotDate)) >= date('Y-m-d')
+            ||
+            date('n',strtotime($slotDate)) == date('n')
+            ||
+            (
+                date('n',strtotime($slotDate)) == date('n', strtotime("-1 month"))
+                &&
+                date('j') <= $days
+            )
+        );
+    }
+
+    public static function getCountDaysAllowEditShift($groupId) : int
+    {
+        $numDay = 5;
+
+        $accessArray = [
+            1, // Директор
+            7, // Кустовые директора
+            8, // Руководитель HR
+            9, // Главный бухгалтер
+            20, // Администратор платформы (HR)
+            51, // Операционный директор
+        ];
+
+        if (in_array($groupId, $accessArray)) {
+            $numDay = 13;
+        }
+
+        return $numDay;
     }
 
     public function getDateTimeStart(): \DateTime
@@ -95,6 +154,7 @@ class Timetable extends ActiveRecord
             'comment' => 'Комментарий',
             'date_add' => 'Дата добавления',
             'status' => 'Статус',
+            'salary_shift' => 'Оклад в смену',
             'datetime_start' => 'Дата и время начала смены',
             'datetime_end' => 'Дата и время окончания смены',
         ];
@@ -184,6 +244,7 @@ class Timetable extends ActiveRecord
             [['tabel'], 'integer', 'skipOnEmpty' => false],
             [['id', 'shift_id', 'store_id'], 'integer'],
 //            [['price_hour'], 'number', 'safe'],
+            [['salary_shift'], 'in', 'range' => self::getSalariesDay(), 'skipOnEmpty' => true],
             [['date'], 'date', 'format' => 'php:Y-m-d'],
             [['shift_id'], 'in', 'range' => array_keys(Shift::all()), 'skipOnEmpty' => false],
             [['store_id'], 'exist', 'targetClass' => CityStore::class, 'targetAttribute' => 'id', 'skipOnEmpty' => false],
@@ -344,4 +405,72 @@ class Timetable extends ActiveRecord
     {
         return $this->hasOne(Shift::class, ['id' => 'shift_id']);
     }
+
+    public static function getAdminsByDates($dateFrom, $dateTo, $employeeSelectStoreId)
+    {
+        $slotTypeId = [
+            Timetable::TIMESLOT_WORK, // "работа"
+        ];
+
+        $timeTableDateList = Timetable::find()
+            ->with('admin')
+            ->with('shift')
+            ->andWhere(['>=', 'date', $dateFrom])
+            ->andWhere(['<=', 'date', $dateTo])
+            ->andWhere(['d_id' => Admin::ADMIN_WORK_GROUP_IDS])
+            ->andWhere(['slot_type_id' => $slotTypeId])
+            ->andWhere(['store_id' => $employeeSelectStoreId])
+            ->andWhere(['tabel' => 0])
+            ->asArray()
+            ->all();
+
+
+        $dateStores = [];
+
+        foreach ($timeTableDateList as $item) {
+            $dateStores[] = [
+                'date' => $item['date'],
+                'store_id' => $item['store_id'],
+            ];
+        }
+
+        foreach ($timeTableDateList as $item) {
+            $keyRow = $item['date'] . '_' . $item['store_id'];
+            $timeTableDateAdminList[$keyRow] = Timetable::find()
+                ->with('admin')
+                ->with('shift')
+                ->andWhere(['date' => $item['date']])
+                ->andWhere(['store_id' => $item['store_id']])
+                ->andWhere(['d_id' => Admin::ADMIN_WORK_GROUP_IDS])
+                ->andWhere(['slot_type_id' => $slotTypeId])
+                ->andWhere(['tabel' => 0])
+                ->asArray()
+                ->all();
+        }
+
+        $adminsPrepared = [];
+        $adminsByDateGuids = [];
+        $adminsByDate = [];
+        if (!empty($timeTableDateAdminList)) {
+            foreach ($timeTableDateAdminList as $keyRow => $itemRows) {
+                $dateKeyPreparedRow = explode('_', $keyRow);
+                $dateKeyRow = ArrayHelper::getValue($dateKeyPreparedRow, array_key_first($dateKeyPreparedRow));
+                foreach ($itemRows as $itemRow) {
+                    $arrayRow = [
+                        'admin_id' => $itemRow['admin']['id'],
+                        'admin_guid' => $itemRow['admin']['guid'],
+                        'admin_name' => $itemRow['admin']['name'],
+                    ];
+                    $adminsPrepared[$keyRow][] = $arrayRow;
+                    $adminsByDate[$dateKeyRow][] = $arrayRow;
+                    $adminsByDateGuids[$dateKeyRow][] = $itemRow['admin']['guid'];
+                }
+            }
+        }
+
+        return [
+            'dateGuids' => $adminsByDateGuids,
+            'dateAdmins' => $adminsByDate,
+        ];
+    }
 }
\ No newline at end of file
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/erp24/records/metrics/FotMetrics.php b/erp24/records/metrics/FotMetrics.php
new file mode 100644 (file)
index 0000000..1aef498
--- /dev/null
@@ -0,0 +1,78 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use yii\db\Expression;
+use yii_app\records\AdminPayrollDays;
+use yii_app\records\metrics\Metrics;
+
+class FotMetrics extends Metrics
+{
+
+    protected bool $calculateDay = false;
+
+    protected array $alias = [
+        'sales_sum_admin',
+        'day_payroll',
+        'admin_count'
+    ];
+
+    protected function getQueryDataDay(): bool
+    {
+        return false;
+    }
+
+    protected function getQueryDataShifts(): \yii\db\ActiveQuery
+    {
+        return AdminPayrollDays::find()
+            ->select([
+                'date' => 'admin_payroll_days.date',
+                'shift_type' => 'admin_payroll_days.smena_type',
+                'store_dynamic_id' => 'store_dynamic.id',
+                'store_id' => 'city_store.id',
+                'day_payroll' => 'SUM(admin_payroll_days.day_payroll)',
+                'sales_sum_admin' => 'SUM(admin_payroll_days.sales_sum)',
+                'admin_count' => 'COUNT(admin_payroll_days.admin_id)',
+            ])
+            ->innerJoin('city_store', 'admin_payroll_days.store_id = city_store.id')
+            ->innerJoin('store_dynamic',
+                [
+                    'AND',
+                    'store_dynamic.store_id = city_store.id',
+                    [
+                        '<=',
+                        new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(admin_payroll_days.date, \'%Y-%m-%d\')')
+                    ],
+                    [
+                        '>',
+                        new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(admin_payroll_days.date, \'%Y-%m-%d\')')
+                    ],
+                ])
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $this->cluster,
+                'city_store.id' => $this->store,
+            ])
+            ->andWhere([
+                'AND',
+                ['admin_payroll_days.smena_type' => [1, 2]],
+                [
+                    '>=',
+                    'DATE_FORMAT(admin_payroll_days.date, \'%Y-%m-%d\')',
+                    $this->dateStart
+                ],
+                [
+                    '<=',
+                    'DATE_FORMAT(admin_payroll_days.date, \'%Y-%m-%d\')',
+                    $this->dateEnd
+                ],
+            ])
+            ->addGroupBy([
+                'admin_payroll_days.date',
+                'admin_payroll_days.smena_type',
+                'store_dynamic.id',
+                'city_store.id'
+            ]);
+    }
+}
\ No newline at end of file
diff --git a/erp24/records/metrics/MatrixMetrics.php b/erp24/records/metrics/MatrixMetrics.php
new file mode 100644 (file)
index 0000000..bb0be69
--- /dev/null
@@ -0,0 +1,181 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use yii\helpers\ArrayHelper;
+use yii_app\records\metrics\Metrics;
+use yii_app\records\Products1c;
+
+class MatrixMetrics extends SalesMetrics
+{
+
+    private array $matrixGroupSearchGuidDictionary;
+    private array $matrixGroupSearchGuid;
+
+    private array $guids;
+
+    protected array $alias = [
+        'matrix_base_summ',
+        'matrix_season_summ',
+        'matrix_new_summ'
+    ];
+
+    protected array $listSelectedQuery = [
+        'matrix_base_summ' => 'SUM(IF (:baseGuids LIKE CONCAT("%", products_1c.id, "%"), sales_products.summ, 0))', // Базовая
+        'matrix_season_summ' => 'SUM(IF (:seasonGuids LIKE CONCAT("%", products_1c.id, "%"), sales_products.summ, 0))', // Сезонная
+        'matrix_new_summ' => 'SUM(IF (:newGuids LIKE CONCAT("%", products_1c.id, "%"), sales_products.summ, 0))' // Новая
+    ];
+
+    protected function loadDefaultValues()
+    {
+        $this->getMatrixSearchGroupId();
+        $this->guids = $this->getGuidsArray();
+    }
+
+    protected function getQueryDataDay(): \yii\db\ActiveQuery
+    {
+        return parent::getQueryDataDay()
+            ->innerJoin('sales_products', 'sales.id = sales_products.check_id')
+            ->innerJoin('products_1c', 'sales_products.product_id = products_1c.id')
+            ->params([
+                ':baseGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Сезонная матрица']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Сезонная матрица']]) : '',
+                ':seasonGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Матрица базовая']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Матрица базовая']]) : '',
+                ':newGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Новая матрица']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Новая матрица']]) : '',
+            ]);
+
+    }
+
+    protected function getQueryDataShifts(): \yii\db\ActiveQuery
+    {
+        return parent::getQueryDataShifts()
+            ->innerJoin('sales_products', 'sales.id = sales_products.check_id')
+            ->innerJoin('products_1c', 'sales_products.product_id = products_1c.id')
+            ->params([
+                ':baseGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Сезонная матрица']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Сезонная матрица']]) : '',
+                ':seasonGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Матрица базовая']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Матрица базовая']]) : '',
+                ':newGuids' => isset($this->guids[$this->matrixGroupSearchGuidDictionary['Новая матрица']]) ? implode("/", $this->guids[$this->matrixGroupSearchGuidDictionary['Новая матрица']]) : '',
+            ]);
+    }
+
+    private function getArrayIndexParentId($array): array
+    {
+        $answer = [];
+
+        foreach ($array as $item) {
+            $answer[$item['parent_id']][] = $item;
+        }
+
+        return $answer;
+    }
+
+    private function getTreeMatrixGroup($array, $parent_id = null, $treeGuid = null): array
+    {
+        $tree = [];
+
+        if ($parent_id === null) {
+            foreach ($array[""] as $item) {
+                if ($item['name'] === 'МАТРИЦА') {
+                    $tree[$item['id']]['name'] = $item['name'];
+                    $tree[$item['id']]['treeGuid'] = '/' . $item['id'] . '/';
+                    $tree[$item['id']]['group'] = $this->getTreeMatrixGroup($array, $item['id'], $tree[$item['id']]['treeGuid']);
+                    $tree[$item['id']]['items'] = [];
+                }
+            }
+        } else {
+            if (isset($array[$parent_id])) {
+                foreach ($array[$parent_id] as $item) {
+                    if ($item['tip'] === 'products_group') {
+                        $tree[$item['id']]['name'] = $item['name'];
+                        $tree[$item['id']]['id'] = $item['id'];
+                        $tree[$item['id']]['treeGuid'] = $treeGuid . $item['id'] . '/';
+                        $tree[$item['id']]['group'] = $this->getTreeMatrixGroup($array, $item['id'], $tree[$item['id']]['treeGuid']);
+
+                        if (isset($array[$item['id']])) {
+                            foreach ($array[$item['id']] as $product) {
+                                if ($product['tip'] === 'products') {
+                                    $tree[$item['id']]['items'][$product['id']]['name'] = $product['name'];
+                                    $tree[$item['id']]['items'][$product['id']]['id'] = $product['id'];
+                                    $tree[$item['id']]['items'][$product['id']]['treeGuid'] = $treeGuid . $item['id'] . '/' . $product['id'] . '/';
+                                }
+                            }
+
+                        } else {
+                            $tree[$item['id']]['items'] = [];
+
+                        }
+                    }
+                }
+            }
+        }
+
+        return $tree;
+    }
+
+    private function getTreeMatrix(): array
+    {
+        $products = Products1c::find()
+            ->select([
+                'id',
+                'parent_id',
+                'name',
+                'tip'
+            ])
+            ->asArray()
+            ->all();
+
+        $productsTree = $this->getArrayIndexParentId($products);
+
+        return $this->getTreeMatrixGroup($productsTree);
+    }
+
+
+    private function getGuidProductsInGroup($tree, &$array, $guids, $guid = null): void
+    {
+        foreach ($tree['group'] as $item) {
+            if (in_array($item['id'], $guids)) {
+                $this->getGuidProductsInGroup($tree['group'][$item['id']], $array, $guids, $item['id']);
+            } else if (!in_array($item['id'], $guids) && $guid != null) {
+                $this->getGuidProductsInGroup($tree['group'][$item['id']], $array, $guids, $guid);
+            }
+        }
+
+        if ($guid != null) {
+            foreach ($tree['items'] as $item) {
+                $array[$guid][] = $item['id'];
+            }
+        }
+
+
+    }
+
+    private function getGuidsArray()
+    {
+        $tree = $this->getTreeMatrix();
+
+        $parentId = array_key_first($tree);
+        $array = [];
+
+        $this->getGuidProductsInGroup($tree[$parentId], $array, $this->matrixGroupSearchGuid);
+
+        return $array;
+    }
+
+    private function getMatrixSearchGroupId()
+    {
+        $matrix_season_guid = Products1c::find()->where(['LIKE', 'name', 'Сезонная матрица'])->select(['id'])->column()[0] ?? '';
+        $matrix_base_guid = Products1c::find()->where(['LIKE', 'name', 'Матрица базовая'])->select(['id'])->column()[0] ?? '';
+        $matrix_new_guid = Products1c::find()->where(['LIKE', 'name', 'Новая матрица'])->select(['id'])->column()[0] ?? '';
+
+        $this->matrixGroupSearchGuid = [
+            $matrix_season_guid,
+            $matrix_base_guid,
+            $matrix_new_guid
+        ];
+
+        $this->matrixGroupSearchGuidDictionary = [
+            'Сезонная матрица' => $matrix_season_guid,
+            'Матрица базовая' => $matrix_base_guid,
+            'Новая матрица' => $matrix_new_guid
+        ];
+    }
+}
\ No newline at end of file
diff --git a/erp24/records/metrics/Metrics.php b/erp24/records/metrics/Metrics.php
new file mode 100755 (executable)
index 0000000..12b3250
--- /dev/null
@@ -0,0 +1,366 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use Yii;
+use yii\base\Model;
+use yii\db\Exception;
+use yii\db\Expression;
+use yii\db\Query;
+use yii\helpers\ArrayHelper;
+use yii_app\records\RnpAlias;
+use yii_app\records\RnpData;
+use yii_app\records\RnpIndex;
+use yii_app\records\StoreDynamic;
+
+abstract class Metrics extends Model
+{
+    public function rules()
+    {
+        return [
+            [['cluster', 'store'], 'safe'],
+            [['dateStart', 'dateEnd'], 'date', 'format' => 'php:Y-m-d'],
+            ['dateStart', 'compare', 'compareAttribute' => 'dateEnd', 'operator' => '<='],
+        ];
+    }
+
+    public $dateStart;
+
+    public $dateEnd;
+
+    public $cluster;
+
+    public $store;
+
+    protected array $alias = [];
+
+    protected array $selectQuery = [];
+
+    protected array $listOfExceptionsByShiftType = [
+        1 => [
+
+        ],
+        2 => [
+
+        ],
+        4 => [
+
+        ],
+    ];
+
+    protected bool $calculateShifts = true;
+
+    protected bool $calculateDay = true;
+
+    private bool $calculateIndex = false;
+
+    protected function loadDefaultValues()
+    {
+
+    }
+
+    protected function loadSelectQuery()
+    {
+        $temp = [];
+
+        foreach ($this->alias as $alias) {
+            if ($this->calculateShifts && $this->calculateDay) {
+                $temp[$alias] = "IF (shift_types.shift_type != 4, data_shifts.$alias, data_day.$alias)";
+            } else if ($this->calculateShifts) {
+                $temp[$alias] = "data_shifts.$alias";
+            } else if ($this->calculateDay) {
+                $temp[$alias] = "data_day.$alias";
+            }
+        }
+
+        $this->selectQuery = $temp;
+    }
+
+    protected abstract function getQueryDataDay();
+
+    protected abstract function getQueryDataShifts();
+
+    final public function insertData(): string
+    {
+        if (!$this->validate()) {
+            return 'Неккоректные свойства объекта';
+        }
+
+        $message = "";
+
+        $start = microtime(true);
+
+        $query = $this->getQueryDataCollection();
+        $dataBatch = $query->asArray()->batch(1000);
+
+        $this->calculateShifts = false;
+        $this->calculateDay = false;
+        $this->calculateIndex = true;
+
+        $indexQuery = $this->getQueryDataCollection();
+
+        $rnpOldIndex = RnpIndex::find()
+            ->where(['BETWEEN', 'date', $this->dateStart, $this->dateEnd])
+            ->select([
+                'index' => 'CONCAT(rnp_index.cluster_id, rnp_index.store_id, rnp_index.date, rnp_index.shift_type)'
+            ])
+            ->indexBy('index')
+            ->asArray()
+            ->all();
+
+        $rnpNewIndex = $indexQuery
+            ->addSelect([
+                'index' => 'CONCAT(store_dynamic.value_int, city_store.id, dates_column.date, shift_types.shift_type)',
+            ])
+            ->indexBy('index')
+            ->asArray()
+            ->all();
+
+
+        $rnpIndexData = array_diff_key($rnpNewIndex, $rnpOldIndex);
+
+        $timeSearch = sprintf('%.6f sec.', microtime(true) - $start);
+
+        $start = microtime(true);
+
+        if (count($rnpIndexData) > 0) {
+            $rnpIndexRows = [];
+            foreach ($rnpIndexData as $index) {
+                $rnpIndexRows[] = [$index['cluster_id'], $index['store_id'], $index['shift_type'], $index['date']];
+            }
+
+            try {
+                $transaction = \Yii::$app->db->beginTransaction();
+                Yii::$app->db->createCommand()->batchInsert('rnp_index', ['cluster_id', 'store_id', 'shift_type', 'date'], $rnpIndexRows)->execute();
+                $transaction->commit();
+
+            } catch (\Exception $exception) {
+                $transaction->rollBack();
+
+                $message .= "\nИНДЕКСЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+                $message .= $exception->getMessage() . "\n";
+            }
+        }
+
+
+        $timeInsertIndex = sprintf('%.6f sec.', microtime(true) - $start);
+
+        $aliases = RnpAlias::find()->select(['id', 'alias'])->asArray()->all();
+
+        $aliases = ArrayHelper::map($aliases, 'alias', 'id');
+
+        $rnp_old_index = RnpIndex::find()->where(['BETWEEN', 'date', $this->dateStart, $this->dateEnd])->select([
+            'id',
+            'cluster_id',
+            'store_id',
+            'shift_type',
+            'date',
+        ])->asArray()->all();
+
+        $ids = [];
+        foreach ($rnp_old_index as $index) {
+            $ids[$index['cluster_id'] . $index['store_id'] . $index['shift_type'] . $index['date']] = $index['id'];
+        }
+
+        $start = microtime(true);
+
+        $rnpDataRows = [];
+        $rnpIndexId = [];
+        foreach ($dataBatch as $data) {
+            foreach ($data as $datum) {
+                $id = -1;
+
+                if (array_key_exists($datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date'], $ids)) {
+                    $id = $ids[$datum['cluster_id'] . $datum['store_id'] . $datum['shift_type'] . $datum['date']];
+                }
+
+                if ($id != -1) {
+                    foreach ($datum as $key => $item) {
+                        if (!in_array($key, ['cluster_id', 'store_id', 'date', 'shift_type', 'store_name']) && !in_array($key, $this->listOfExceptionsByShiftType[$datum['shift_type']])) {
+                            $rnpDataRows[] = [$id, $aliases[$key], $item ? round($item, 2) : 0];
+                            $rnpIndexId[] = $id;
+                        }
+                    }
+                }
+            }
+        }
+
+        try {
+            $transaction = \Yii::$app->db->beginTransaction();
+            RnpData::deleteAll(
+                [
+                    'AND',
+                    ['index_id' => $rnpIndexId],
+                    [
+                        'IN',
+                        'alias_id',
+                        RnpAlias::find()
+                            ->select('id')
+                            ->where(['alias' => $this->alias])
+                    ]
+                ]
+            );
+            Yii::$app->db->createCommand()->batchInsert('rnp_data', ['index_id', 'alias_id', 'value'], $rnpDataRows)->execute();
+            $transaction->commit();
+
+        } catch (\Exception $exception) {
+            $transaction->rollBack();
+
+            $message .= "\nАТРИБУТЫ НЕ УДАЛОСЬ СОХРАНИТЬ -\n";
+            $message .= $exception->getMessage() . "\n";
+        }
+
+        $timeInsertData = sprintf('%.6f sec.', microtime(true) - $start);
+
+        $message .= "\n|Время поиска: $timeSearch|Время записи индексов: $timeInsertIndex|Время записи данных: $timeInsertData|\n";
+
+        return $message;
+    }
+
+    final public function getQueryDataCollection(): \yii\db\ActiveQuery
+    {
+        $this->loadDefaultValues();
+
+        $this->loadSelectQuery();
+
+        $datesQuery = (new Query())->from('(
+                SELECT :date_end - INTERVAL (units.mul + (10 * tens.mul) + (100 * hundreds.mul) + (1000 * thousands.mul)) DAY AS date
+                FROM       (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS units
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS tens
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS hundreds
+                CROSS JOIN (SELECT 0 AS mul UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) AS thousands
+            ) a'
+        )
+            ->params([':date_end' => $this->dateEnd])
+            ->andWhere([
+                'BETWEEN', 'a.date', $this->dateStart, $this->dateEnd
+            ])
+            ->orderBy(['date' => SORT_ASC]);
+
+        $shiftsQuerySelect = '';
+
+        if ($this->calculateShifts && $this->calculateDay || $this->calculateIndex) {
+            $shiftsQuerySelect = '(
+                SELECT 1 AS shift_type UNION ALL SELECT 2 UNION ALL SELECT 4
+            ) shift_types';
+
+        } else if ($this->calculateShifts) {
+            $shiftsQuerySelect = '(
+                SELECT 1 AS shift_type UNION ALL SELECT 2
+            ) shift_types';
+
+        } else if ($this->calculateDay) {
+            $shiftsQuerySelect = '(
+                SELECT 4 AS shift_type
+            ) shift_types';
+
+        }
+
+        $shiftQuery = (new Query())->from(
+            $shiftsQuerySelect
+        )
+            ->select(['shift_type' => 'shift_types.shift_type']);
+
+        $query = StoreDynamic::find()
+            ->select(array_merge(
+                [
+                    'date' => 'dates_column.date',
+                    'shift_type' => 'shift_types.shift_type',
+                    'cluster_id' => 'store_dynamic.value_int',
+                    'store_id' => 'city_store.id',
+                ],
+                $this->calculateIndex ? [] : $this->selectQuery
+            ))
+            ->innerJoin('city_store', 'store_dynamic.store_id = city_store.id  AND store_dynamic.category = 1')
+            ->leftJoin(
+                ['dates_column' => $datesQuery],
+                [
+                    'BETWEEN',
+                    'dates_column.date',
+                    new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                    new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                ]
+            )
+            ->leftJoin(['shift_types' => $shiftQuery], '1=1');
+
+
+        if ($this->calculateShifts) {
+            $query->leftJoin(
+                ['data_shifts' => $this->getQueryDataShifts()],
+                [
+                    'AND',
+                    'city_store.id = data_shifts.store_id',
+                    'store_dynamic.id = data_shifts.store_dynamic_id',
+                    'dates_column.date = data_shifts.date',
+                    'shift_types.shift_type = data_shifts.shift_type'
+                ]
+            );
+        }
+
+        if ($this->calculateDay) {
+            $query->leftJoin(
+                ['data_day' => $this->getQueryDataDay()],
+                [
+                    'AND',
+                    'city_store.id = data_day.store_id',
+                    'store_dynamic.id = data_day.store_dynamic_id',
+                    'dates_column.date = data_day.date',
+                    'shift_types.shift_type = data_day.shift_type'
+                ]
+            );
+        }
+
+        $query->andWhere([
+            'AND',
+            ['>=', 'dates_column.date', $this->dateStart],
+            ['<=', 'dates_column.date', $this->dateEnd]
+        ])
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $this->cluster,
+                'city_store.id' => $this->store,
+            ]);
+
+        return $query;
+    }
+
+    final protected function getDataArray($clusterId, $storeId, $shift): array
+    {
+        return RnpData::find()
+            ->select([
+                'date' => 'rnp_index.date',
+                'shift' => 'rnp_index.shift_type',
+                'alias' => 'rnp_alias.alias',
+                'value' => 'rnp_data.value'
+            ])
+            ->innerJoin('rnp_alias', 'rnp_data.alias_id = rnp_alias.id')
+            ->innerJoin('rnp_index', 'rnp_data.index_id = rnp_index.id')
+            ->andWhere([
+                'AND',
+                [
+                    'rnp_alias.alias' => $this->alias
+                ],
+                [
+                    '>=',
+                    'rnp_index.date',
+                    $this->dateStart
+                ],
+                [
+                    '<=',
+                    'rnp_index.date',
+                    $this->dateEnd
+                ]
+            ])
+            ->andFilterWhere([
+                'rnp_index.cluster_id' => $clusterId,
+                'rnp_index.store_id' => $storeId,
+                'rnp_index.shift_type' => $shift
+            ])
+            ->orderBy([
+                'rnp_index.date' => SORT_ASC,
+                'rnp_index.shift_type' => SORT_ASC,
+                'rnp_alias.id' => SORT_ASC
+            ])
+            ->asArray()
+            ->all();
+    }
+}
\ No newline at end of file
diff --git a/erp24/records/metrics/SalesMetrics.php b/erp24/records/metrics/SalesMetrics.php
new file mode 100644 (file)
index 0000000..34646f3
--- /dev/null
@@ -0,0 +1,274 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use Exception;
+use yii\db\Expression;
+use yii_app\records\RnpData;
+use yii_app\records\Sales;
+
+class SalesMetrics extends Metrics
+{
+    protected array $alias = [
+        'sales_sum',
+        'count_sales',
+        'count_sales_in_0_hour',
+        'count_sales_in_1_hour',
+        'count_sales_in_2_hour',
+        'count_sales_in_3_hour',
+        'count_sales_in_4_hour',
+        'count_sales_in_5_hour',
+        'count_sales_in_6_hour',
+        'count_sales_in_7_hour',
+        'count_sales_in_8_hour',
+        'count_sales_in_9_hour',
+        'count_sales_in_10_hour',
+        'count_sales_in_11_hour',
+        'count_sales_in_12_hour',
+        'count_sales_in_13_hour',
+        'count_sales_in_14_hour',
+        'count_sales_in_15_hour',
+        'count_sales_in_16_hour',
+        'count_sales_in_17_hour',
+        'count_sales_in_18_hour',
+        'count_sales_in_19_hour',
+        'count_sales_in_20_hour',
+        'count_sales_in_21_hour',
+        'count_sales_in_22_hour',
+        'count_sales_in_23_hour',
+    ];
+
+    protected array $listOfExceptionsByShiftType = [
+        1 => [
+            'count_sales_in_0_hour',
+            'count_sales_in_1_hour',
+            'count_sales_in_2_hour',
+            'count_sales_in_3_hour',
+            'count_sales_in_4_hour',
+            'count_sales_in_5_hour',
+            'count_sales_in_6_hour',
+            'count_sales_in_7_hour',
+            'count_sales_in_20_hour',
+            'count_sales_in_21_hour',
+            'count_sales_in_22_hour',
+            'count_sales_in_23_hour',
+        ],
+        2 => [
+            'count_sales_in_8_hour',
+            'count_sales_in_9_hour',
+            'count_sales_in_10_hour',
+            'count_sales_in_11_hour',
+            'count_sales_in_12_hour',
+            'count_sales_in_13_hour',
+            'count_sales_in_14_hour',
+            'count_sales_in_15_hour',
+            'count_sales_in_16_hour',
+            'count_sales_in_17_hour',
+            'count_sales_in_18_hour',
+            'count_sales_in_19_hour',
+        ],
+        4 => [
+
+        ],
+    ];
+
+    protected array $listSelectedQuery = [
+        'sales_sum' => 'SUM(IF(sales.sales_check = \'\', sales.summ, 0)) - SUM(IF(sales.sales_check != \'\', sales.summ, 0))',
+        //'sales_sum' => 'SUM(sales.summ)',
+        'count_sales' => 'COUNT(sales.id)',
+        'count_sales_in_0_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 0, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 0, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_1_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 1, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 1, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_2_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 2, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 2, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_3_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 3, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 3, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_4_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 4, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 4, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_5_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 5, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 5, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_6_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 6, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 6, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_7_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 7, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 7, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_8_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 8, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 8, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_9_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 9, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 9, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_10_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 10, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 10, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_11_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 11, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 11, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_12_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 12, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 12, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_13_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 13, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 13, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_14_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 14, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 14, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_15_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 15, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 15, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_16_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 16, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 16, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_17_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 17, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 17, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_18_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 18, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 18, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_19_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 19, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 19, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_20_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 20, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 20, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_21_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 21, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 21, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_22_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 22, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 22, 59, 59), \'%H:%i:%s\'), 1, 0))',
+        'count_sales_in_23_hour' => 'SUM(if (TIME_FORMAT(sales.date, \'%H:%i:%s\') >= TIME_FORMAT(CONCAT_WS(\':\', 23, 0, 0), \'%H:%i:%s\') AND TIME_FORMAT(sales.date, \'%H:%i:%s\') <= TIME_FORMAT(CONCAT_WS(\':\', 23, 59, 59), \'%H:%i:%s\'), 1, 0))',
+    ];
+
+    protected function getQueryDataDay(): \yii\db\ActiveQuery
+    {
+        return Sales::find()
+            ->select(array_merge(
+                [
+                    'date' => 'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                    'store_id' => 'city_store.id',
+                    'store_dynamic_id' => 'store_dynamic.id',
+                    'shift_type' => '(SELECT 4 AS shift_type)',
+                ],
+                $this->listSelectedQuery
+            ))
+            ->innerJoin('city_store', 'sales.store_id = city_store.id')
+            ->innerJoin('store_dynamic',
+                [
+                    'AND',
+                    [
+                        '=',
+                        new Expression('store_dynamic.store_id'),
+                        new Expression('city_store.id')
+                    ],
+                    [
+                        '<=',
+                        new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
+                    ],
+                    [
+                        '>',
+                        new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(sales.date, \'%Y-%m-%d\')')
+                    ]
+                ]
+            )
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $this->cluster,
+                'city_store.id' => $this->store,
+            ])
+            ->andWhere([
+                'AND',
+                [
+                    '>=',
+                    'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                    $this->dateStart
+                ],
+                [
+                    '<=',
+                    'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                    $this->dateEnd
+                ],
+                /*[
+                    'NOT IN',
+                    'sales.id',
+                    Sales::find()
+                        ->select([
+                            'id' => 'sales.sales_check'
+                        ])
+                        ->andWhere([
+                            'AND',
+                            [
+                                '>=',
+                                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                                $this->dateStart
+                            ],
+                            [
+                                '<',
+                                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                                date('Y-m-d', strtotime('+1 week', strtotime($this->dateEnd)))
+                            ],
+                        ])
+                ],*/
+                ['sales.operation' => 'Продажа'],
+                ['sales.order_id' => '']
+            ])
+            ->groupBy([
+                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')',
+                'city_store.id',
+                'store_dynamic.id'
+            ])
+            ->orderBy([
+                'DATE_FORMAT(sales.date, \'%Y-%m-%d\')' => SORT_ASC,
+                'city_store.id' => SORT_ASC
+            ]);
+    }
+
+    protected function getQueryDataShifts(): \yii\db\ActiveQuery
+    {
+        return Sales::find()
+            ->select(array_merge(
+                [
+                    'date' => 'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                    'store_id' => 'city_store.id',
+                    'store_dynamic_id' => 'store_dynamic.id',
+                    'shift_type' => 'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+                ],
+                $this->listSelectedQuery
+            ))
+            ->innerJoin('city_store', 'sales.store_id = city_store.id')
+            ->innerJoin('store_dynamic',
+                [
+                    'AND',
+                    [
+                        '=',
+                        new Expression('store_dynamic.store_id'),
+                        new Expression('city_store.id')
+                    ],
+                    [
+                        '<=',
+                        new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                        new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    ],
+                    [
+                        '>',
+                        new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                        new Expression('if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))')
+                    ]
+                ]
+            )
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $this->cluster,
+                'city_store.id' => $this->store,
+            ])
+            ->andWhere([
+                'AND',
+                [
+                    '>=',
+                    'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                    $this->dateStart
+                ],
+                [
+                    '<=',
+                    'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                    $this->dateEnd
+                ],
+                /*[
+                    'NOT IN',
+                    'sales.id',
+                    Sales::find()
+                        ->select([
+                            'id' => 'sales.sales_check'
+                        ])
+                        ->andWhere([
+                            'AND',
+                            [
+                                '>=',
+                                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                                $this->dateStart
+                            ],
+                            [
+                                '<',
+                                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                                date('Y-m-d', strtotime('+1 week', strtotime($this->dateEnd)))
+                            ],
+                        ])
+                ],*/
+                ['sales.operation' => 'Продажа'],
+                ['sales.order_id' => '']
+            ])
+            ->groupBy([
+                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))',
+                'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)',
+                'city_store.id',
+                'store_dynamic.id'
+            ])
+            ->orderBy([
+                'if (HOUR(sales.date) < 8, DATE_FORMAT(DATE_SUB(sales.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(sales.date, \'%Y-%m-%d\'))' => SORT_ASC,
+                'if(HOUR(sales.date) >= 8 && HOUR(sales.date) < 20, 1, 2)' => SORT_ASC,
+                'city_store.id' => SORT_ASC
+            ]);
+    }
+}
\ No newline at end of file
diff --git a/erp24/records/metrics/UserBonusMetrics.php b/erp24/records/metrics/UserBonusMetrics.php
new file mode 100644 (file)
index 0000000..9461d04
--- /dev/null
@@ -0,0 +1,94 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use yii\db\Expression;
+use yii_app\records\metrics\Metrics;
+use yii_app\records\Sales;
+use yii_app\records\UsersBonus;
+
+class UserBonusMetrics extends SalesMetrics
+{
+    protected array $alias = [
+        'count_users',
+        'first_minus_user_bonus',
+        'second_minus_user_bonus'
+    ];
+
+    protected array $listSelectedQuery = [
+        'count_users' => 'SUM( IF (sales.phone IS NOT NULL AND sales.phone != \'\', 1, 0))',
+        'first_minus_user_bonus' => 'SUM( IF (users.first_minus_balance = sub_users_bonus.date, 1, 0))',
+        'second_minus_user_bonus' => 'SUM( IF (users.first_minus_balance < sub_users_bonus.date, 1, 0))',
+    ];
+
+    protected function getQueryDataDay(): \yii\db\ActiveQuery
+    {
+        $subUsersBonusQuery = UsersBonus::find()
+            ->select([
+                'users_bonus.user_id',
+                'users_bonus.check_id',
+                'users_bonus.date'
+            ])
+            ->andWhere([
+                'AND',
+                ['>=', 'DATE_FORMAT(users_bonus.date, \'%Y-%m-%d\')', $this->dateStart],
+                ['<=', 'DATE_FORMAT(users_bonus.date, \'%Y-%m-%d\')', $this->dateStart],
+                ['!=', 'users_bonus.check_id', ''],
+                ['users_bonus.tip' => 'minus'],
+            ]);
+
+        return parent::getQueryDataDay()
+            ->leftJoin('users', 'sales.phone = users.phone')
+            ->leftJoin(['sub_users_bonus' => $subUsersBonusQuery],
+                [
+                    'AND',
+                    [
+                        '=',
+                        new Expression('users.id'),
+                        new Expression('sub_users_bonus.user_id')
+                    ],
+                    [
+                        '=',
+                        new Expression('sales.id'),
+                        new Expression('sub_users_bonus.check_id')
+                    ],
+                ]
+            );
+    }
+
+    protected function getQueryDataShifts(): \yii\db\ActiveQuery
+    {
+
+        $subUsersBonusQuery = UsersBonus::find()
+            ->select([
+                'users_bonus.user_id',
+                'users_bonus.check_id',
+                'users_bonus.date'
+            ])
+            ->andWhere([
+                'AND',
+                ['>=', 'if (HOUR(users_bonus.date) < 8, DATE_FORMAT(DATE_SUB(users_bonus.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(users_bonus.date, \'%Y-%m-%d\'))', $this->dateStart],
+                ['<=', 'if (HOUR(users_bonus.date) < 8, DATE_FORMAT(DATE_SUB(users_bonus.date, INTERVAL 1 DAY), \'%Y-%m-%d\'), DATE_FORMAT(users_bonus.date, \'%Y-%m-%d\'))', $this->dateStart],
+                ['!=', 'users_bonus.check_id', ''],
+                ['users_bonus.tip' => 'minus'],
+            ]);
+
+        return parent::getQueryDataShifts()
+            ->leftJoin('users', 'sales.phone = users.phone')
+            ->leftJoin(['sub_users_bonus' => $subUsersBonusQuery],
+                [
+                    'AND',
+                    [
+                        '=',
+                        new Expression('users.id'),
+                        new Expression('sub_users_bonus.user_id')
+                    ],
+                    [
+                        '=',
+                        new Expression('sales.id'),
+                        new Expression('sub_users_bonus.check_id')
+                    ],
+                ]
+            );
+    }
+}
\ No newline at end of file
diff --git a/erp24/records/metrics/WriteOffsMetrics.php b/erp24/records/metrics/WriteOffsMetrics.php
new file mode 100644 (file)
index 0000000..b0422e6
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+namespace yii_app\records\metrics;
+
+use yii\db\Expression;
+use yii_app\records\metrics\Metrics;
+use yii_app\records\WriteOffs;
+
+class WriteOffsMetrics extends Metrics
+{
+    protected array $alias = [
+        'write_offs'
+    ];
+
+    protected bool $calculateShifts = false;
+
+    protected function getQueryDataDay()
+    {
+        return WriteOffs::find()
+            ->select([
+                'date' => 'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
+                'shift_type' => '(SELECT 4)',
+                'store_dynamic_id' => 'store_dynamic.id',
+                'store_id' => 'city_store.id',
+                'write_offs' => 'SUM(write_offs.summ)',
+            ])
+            ->innerJoin('export_import_table', 'write_offs.store_id = export_import_table.export_val')
+            ->innerJoin('city_store', 'export_import_table.entity_id = city_store.id')
+            ->innerJoin(
+                'store_dynamic',
+                [
+                    'AND',
+                    'store_dynamic.store_id = export_import_table.entity_id',
+                    [
+                        '<=',
+                        new Expression('DATE_FORMAT(store_dynamic.date_from, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
+                    ],
+                    [
+                        '>',
+                        new Expression('DATE_FORMAT(store_dynamic.date_to, \'%Y-%m-%d\')'),
+                        new Expression('DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')')
+                    ],
+                ]
+            )
+            ->andFilterWhere([
+                'store_dynamic.value_int' => $this->cluster,
+                'city_store.id' => $this->store,
+            ])
+            ->andWhere([
+                'AND',
+                ['write_offs.type' => 'Брак'],
+                ['>=', 'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')', $this->dateStart],
+                ['<=', 'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')', $this->dateEnd]
+            ])
+            ->addGroupBy([
+                'DATE_FORMAT(write_offs.date, \'%Y-%m-%d\')',
+                'store_dynamic.id',
+                'city_store.id'
+            ]);
+    }
+
+    protected function getQueryDataShifts(): bool
+    {
+        return false;
+    }
+}
\ No newline at end of file
index 9aab158c4e660538df4ee94583f8bd9700108b8a..aca200c868df4e802613fc4671d1290a91d9d003 100755 (executable)
@@ -83,13 +83,13 @@ try {
         $paramMinusDays = null;
         $dayMonthNum = date("j", time());
 
-//        if ('22' . $dateTimeMinuet == $timeGi) {
-//            $paramDateFrom = date("Y-m-01", time());
-//        }
+        if ('22' . $dateTimeMinuet == $timeGi) {
+            $paramDateFrom = date("Y-m-01", time());
+        }
 
-//        if ('07' . $dateTimeMinuet == $timeGi && $dayMonthNum > 7) {
-//            $paramMinusDays = 7;
-//        }
+        if ('07' . $dateTimeMinuet == $timeGi && $dayMonthNum > 7) {
+            $paramMinusDays = 7;
+        }
 
         if ('09' . $dateTimeMinuet == $timeGi && $dayMonthNum > 3) {
             $paramMinusDays = 3;
index 2f6993a6f6f5b12b9ecbc9af0b27e9c41a65d032..127c99a014b3d19bce18768ed9c0ccb6cacb4380 100755 (executable)
@@ -46,7 +46,7 @@ $nmDayStopCalculateLastMonth = 7;
 $minuetTimeInTask = date('i', $time);
 $fullTimeInTask = date('Y-m-d H:i:s', $time);
 
-$condition2 = (date('Gi', $time) == '1030' && date("d") < $nmDayStopCalculateLastMonth);
+$condition2 = (date('Gi', $time) == '0830' && date("d") < $nmDayStopCalculateLastMonth);
 
 
 
@@ -133,6 +133,8 @@ try {
         $info = ' ================ test Task 0' . $taskNum . ' stop ================';
         echo $info;
         $log .= $info;
+        $log .= ' ' . $dateFrom;
+        $log .= ' ' . $dateTo;
         $dateTaskStop = date('Y-m-d H:i:s');
     } else {
         $info = '   Task 0' . $taskNum . ' skip   ';
index b0324f8f5851bce3aa76f9e20216a0cb6dd1a584..78dd7edacf84b6e1eb120a73216bcf085285239b 100644 (file)
@@ -56,9 +56,9 @@ try {
         $infoText .= ' test ';
 
         //////////////////////////////////////////////
-        $sales = Sales::find()->where(['>', 'date', '2023-10-23 00:00:00'])->andWhere(['<=', 'date', '2024-01-07 23:59:59'])
+        $sales = Sales::find()->where(['>', 'date', '2024-01-15 00:00:00'])->andWhere(['<=', 'date', '2024-03-30 23:59:59'])
             ->andWhere(['operation' => 'Продажа'])->andWhere(['>=', 'summ', '2500'])->orderBy(['date' => SORT_ASC])->all();
-        $returns = Sales::find()->where(['>', 'date', '2023-10-23 00:00:00'])->andWhere(['<=', 'date', '2024-01-07 23:59:59'])
+        $returns = Sales::find()->where(['>', 'date', '2024-01-15 00:00:00'])->andWhere(['<=', 'date', '2024-03-30 23:59:59'])
             ->andWhere(['operation' => 'Возврат'])->all();
 
         $returnCheckIds = [];
index 151dc4d4c630bf3551c7945e351aa294e9607bae..4302a4eb5a6bf169299ea2bcc965c2cf3aa627ec 100755 (executable)
@@ -122,6 +122,8 @@ try {
         $info = ' ================ test Task ' . $taskNum . ' stop ================';
         echo $info;
         $log .= $info;
+        $log .= ' ' . $dateFrom;
+        $log .= ' ' . $dateTo;
         $dateTaskStop = date('Y-m-d H:i:s');
     } else {
         $info = '   Task ' . $taskNum . ' skip   ';
index 53b02998b0fd8ba14d977314809236f39048dfec..3172f8b7577b21934ff9061040a19cb919214dbe 100644 (file)
@@ -127,6 +127,8 @@ try {
         $info = ' ================ test Task ' . $taskNum . ' stop ================';
         echo $info;
         $log .= $info;
+        $log .= ' ' . $date_start;
+        $log .= ' ' . $date_end;
         $dateTaskStop = date('Y-m-d H:i:s');
     } else {
         $info = '   Task ' . $taskNum . ' skip   ';
diff --git a/erp24/scripts/tasks/task_21_calculation_company_data_sales.php b/erp24/scripts/tasks/task_21_calculation_company_data_sales.php
new file mode 100644 (file)
index 0000000..2c7e1ee
--- /dev/null
@@ -0,0 +1,135 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\metrics\SalesMetrics;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 21;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0300';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+        )
+        && $enable
+    ) {
+
+
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $salesMetrics = new SalesMetrics();
+        $salesMetrics->dateStart = $dateStart;
+        $salesMetrics->dateEnd = $dateEnd;
+
+
+        $startExecution = microtime( true );
+        $log .= $salesMetrics->insertData();
+        $timeExecution = sprintf( '%.6f sec.', microtime( true ) - $startExecution );
+
+        $log.= "\nВремя выполнения: $timeExecution\n";
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
index 701d0f02d59344a5019533e309d8d4c578e05a4b..1ad061f7626ca07b7742d405be8a470037c41d63 100644 (file)
@@ -4,12 +4,14 @@
  * @var $time integer
  */
 
+use yii\helpers\ArrayHelper;
 use yii_app\helpers\DataHelper;
 use yii_app\records\Admin;
 use yii_app\records\AdminGroup;
 use yii_app\records\EmployeeOnShift;
 use yii_app\records\ExportImportTable;
 use yii_app\records\SchedulerTaskLog;
+use yii_app\services\ExportImportService;
 
 
 ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
@@ -66,28 +68,53 @@ try {
 
         //////////////////////////////////////////////
 
+        $compareDate = date('Y-m-d H:i:s', strtotime("-1 month", time()));
+
+        $entityCityStore = ExportImportService::getEntityByType();
+        $exportCityStore = ArrayHelper::map($entityCityStore, 'entity_id', 'export_val');
+
         $admins = Admin::find()
-            ->select(['id', 'guid', 'name', 'mobile as phone'])
+            ->select(['id', 'guid', 'name', 'store_id', 'mobile as phone'])
             ->where(['and', ['guid' => ''], ['!=', 'mobile', '']])
             ->andWhere(['in', 'group_id', AdminGroup::getGroupsForEmployeeOnCashbox()])
-            ->andWhere(['>=', 'date_add', date('Y-m-d H:i:s', strtotime("-2 hour", time()))])
+            ->andWhere(['>=', 'date_add', $compareDate])
             ->all();
+        $adminsIds = implode(',',ArrayHelper::getColumn($admins, 'id'));
+
+        $phones = ArrayHelper::getColumn(EmployeeOnShift::find()->all(), 'phone');
 
         foreach ($admins as $admin) {
+            /** @var Admin $admin */
+            if (in_array($admin->phone, $phones)) {
+                continue;
+            }
+
+            $storeGuid = '--';
+
+            if (!empty($admin->store_id)) {
+                if (array_key_exists($admin->store_id, $exportCityStore)) {
+                    $storeGuid = $exportCityStore[$admin->store_id];
+                }
+            }
+
             $model = new EmployeeOnShift([
                 'first_name' => $admin->name, 'last_name' => '', 'phone' => $admin->phone,
                 'shift_date' => date('Y-m-d H:i:s'), 'shift_type' => 1,
                 'datetime_start' => date('Y-m-d H:i:s'),
                 'datetime_end' => date('Y-m-d H:i:s'),
                 'created_by' => 1,
-                'store_id' => '-',
+                'store_id' => $storeGuid,
                 'price' => 0,
+                'salary_shift' => 1500,
             ]);
             $model->guid = DataHelper::createGuidMy("06");
             $model->created_at = date("Y-m-d H:i:s");
             $model->status = EmployeeOnShift::STATUS_ACCEPT;
             $model->status_source = EmployeeOnShift::STATUS_SOURCE_NOT_CREATED_IN_1C;
             $model->save();
+            if ($model->getErrors()) {
+                $error .= json_encode($model->getErrors(), JSON_UNESCAPED_UNICODE);
+            }
 
             $admin->guid = $model->guid;
             $admin->save(false);
@@ -105,6 +132,10 @@ try {
         $info = ' ================ test Task ' . $taskNum . ' stop ================';
         echo $info;
         $log .= $info;
+        $log .= ' count($admins) = '. count($admins);
+        $log .= ' $adminsIds = '. $adminsIds;
+        $log .= ' date_add  >='. $compareDate;
+
         $dateTaskStop = date('Y-m-d H:i:s');
     } else {
         $info = '   Task ' . $taskNum . ' skip   ';
diff --git a/erp24/scripts/tasks/task_23_calculation_company_data_users_bonus.php b/erp24/scripts/tasks/task_23_calculation_company_data_users_bonus.php
new file mode 100644 (file)
index 0000000..f5b2c2a
--- /dev/null
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\metrics\UserBonusMetrics;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 23;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0400';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+
+        )
+        && $enable
+    ) {
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $userBonusMetrics = new UserBonusMetrics();
+        $userBonusMetrics->dateStart = $dateStart;
+        $userBonusMetrics->dateEnd = $dateEnd;
+
+        $startExecution = microtime( true );
+        $log .= $userBonusMetrics->insertData();
+        $timeExecution = sprintf( '%.6f sec.', microtime( true ) - $startExecution );
+
+        $log.= "\nВремя выполнения: $timeExecution\n";
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
diff --git a/erp24/scripts/tasks/task_24_calculation_company_data_matrix_sales.php b/erp24/scripts/tasks/task_24_calculation_company_data_matrix_sales.php
new file mode 100644 (file)
index 0000000..312a597
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\metrics\MatrixMetrics;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 24;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0330';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+        )
+        && $enable
+    ) {
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $matrixMetrics = new MatrixMetrics();
+        $matrixMetrics->dateStart = $dateStart;
+        $matrixMetrics->dateEnd = $dateEnd;
+
+        $startExecution = microtime( true );
+        $log .= $matrixMetrics->insertData();
+        $timeExecution = sprintf( '%.6f sec.', microtime( true ) - $startExecution );
+
+        $log.= "\nВремя выполнения: $timeExecution\n";
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage() . ' ' . $e->getFile() . ' >>> ' . $e->getLine();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
index ec15d5f8adf8a54a8c3206083c941029b66c14d2..b27f32d30902dfa42503835b4f8889b0f839a55d 100644 (file)
@@ -6,6 +6,7 @@
 
 use yii\helpers\ArrayHelper;
 
+use yii_app\records\NotifiableUser;
 use yii_app\records\Users;
 use yii_app\records\UsersBonus;
 use yii_app\api3\modules\v1\models\orders\OrdersAmo;
@@ -93,15 +94,15 @@ try {
 
                 $userFound = Users::find()->where(['phone' => $phone])->one();
                 /** @var $userFound Users */
-                $credit_procent = $cnt == 0
-                    && $userFound && $userFound->source > 0
-                    && in_array($sale->store_id_1c, [
-                        '0a575763-8871-11ee-84e2-ac1f6b1b7573', // 31 Энтузиастов 22/18 (Москва)
-                        'e7fc2ba3-8870-11ee-84e2-ac1f6b1b7573'  // 30 Леонова 18 (Москва)
-                    ])
-                    && date('Y-m-d H:i:s') <= '2023-12-25 23:59:59' ? 0.3 : 0.1;
-                $back = round($sale->summ * $credit_procent);
-                $nm = "Возврат с покупки " . (100 * $credit_procent) . "% " . $sale->number . " сумма чека " . $sale->summ;
+                $salesCount = 0;
+                if ($userFound && $userFound->telegram_created_at) {
+                    $salesCount = intval(Sales::find()->where(['phone' => $phone, 'operation' => Sales::OPERATION_SALE])
+                        ->andWhere(['>=', 'date', $userFound->telegram_created_at])->count());
+                }
+                $credit_procent_index = $userFound && $userFound->source > 0 && $salesCount == 0 ? 1 : 0;
+
+                $back1 = $back = round($sale->summ * 0.1);
+                $nm = "Возврат с покупки " . (100 * 0.1) . "% " . $sale->number . " сумма чека " . $sale->summ;
 
                 $userBonus = new UsersBonus;
                 $userBonus->tip = 'plus';
@@ -125,6 +126,46 @@ try {
                 if ($userBonus->getErrors()) {
                     $log .= json_encode($userBonus->getErrors(), JSON_UNESCAPED_UNICODE);
                 }
+                if ($credit_procent_index) {
+                    $back = round($sale->summ * 0.2);
+                    $nm = "Возврат с покупки " . (100 * 0.2) . "% " . $sale->number . " сумма чека " . $sale->summ;
+
+                    $userBonus = new UsersBonus;
+                    $userBonus->tip = 'plus';
+                    $userBonus->tip_sale = 'sale';
+                    $userBonus->date = $sale->date;
+                    $userBonus->date_start = date('Y-m-d H:i:s', strtotime('+1 day', strtotime($userBonus->date)));
+                    $userBonus->date_end = date('Y-m-d H:i:s', strtotime('+3 month', strtotime($userBonus->date)));
+                    $userBonus->phone = $phone;
+                    $userBonus->name = $nm;
+                    $userBonus->check_id = $sale->id;
+                    $userBonus->store_id =
+                    $userBonus->bonus = $back;
+                    $userBonus->site_id = 0;
+                    $userBonus->referal_id = 0;
+                    $userBonus->admin_id = $sale->admin_id;
+                    $userBonus->price = $sale->summ;
+                    $userBonus->store_id_1c = $sale->store_id_1c;
+                    $userBonus->seller_id_1c = $sale->seller_id;
+                    $userBonus->lid_id = $sale->order_id;
+                    $userBonus->save();
+                    if ($userBonus->getErrors()) {
+                        $log .= json_encode($userBonus->getErrors(), JSON_UNESCAPED_UNICODE);
+                    }
+                    if ($userFound->telegram_created_at == null) {
+                        $userFound->telegram_created_at = date("Y-m-d H:i:s");
+                        $userFound->save();
+                        if ($userFound->getErrors()) {
+                            $log .= json_encode(["error_id" => 5.3, "error" => $userFound->getErrors()]);
+                        }
+                    }
+
+                    $notifiableUser = new NotifiableUser;
+                    $notifiableUser->phone = $phone;
+                    $notifiableUser->type = "first_given_bonus";
+                    $notifiableUser->data = "" . ($back1 + $back);
+                    $notifiableUser->save();
+                }
             }
         }
 
index 35c34f08960693ba896bc5f798e155b98c15f4b0..7b912189eb917841e8c48873ed530cba612b0d23 100644 (file)
@@ -11,7 +11,7 @@ use yii_app\records\UsersBonus;
 use yii_app\api3\modules\v1\models\orders\OrdersAmo;
 use yii_app\records\Sales;
 use yii_app\records\SchedulerTaskLog;
-
+use yii_app\records\NotifiableUser;
 
 ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
 ini_set('display_errors', 'on');
@@ -96,15 +96,15 @@ try {
 
                 $userFound = Users::find()->where(['phone' => $phone])->one();
                 /** @var $userFound Users */
-                $credit_procent = $cnt == 0
-                    && $userFound && $userFound->source > 0
-                    && in_array($sale->store_id_1c, [
-                        '0a575763-8871-11ee-84e2-ac1f6b1b7573', // 31 Энтузиастов 22/18 (Москва)
-                        'e7fc2ba3-8870-11ee-84e2-ac1f6b1b7573'  // 30 Леонова 18 (Москва)
-                    ])
-                    && date('Y-m-d H:i:s') <= '2023-12-25 23:59:59' ? 0.3 : 0.1;
-                $back = round($sale->summ * $credit_procent);
-                $nm = "Возврат с покупки " . (100 * $credit_procent) . "% " . $sale->number . " сумма чека " . $sale->summ;
+                $salesCount = 0;
+                if ($userFound && $userFound->telegram_created_at) {
+                    $salesCount = intval(Sales::find()->where(['phone' => $phone, 'operation' => Sales::OPERATION_SALE])
+                        ->andWhere(['>=', 'date', $userFound->telegram_created_at])->count());
+                }
+                $credit_procent_index = $userFound && $userFound->source > 0 && $salesCount == 0 ? 1 : 0;
+
+                $back1 = $back = round($sale->summ * 0.1);
+                $nm = "Возврат с покупки " . (100 * 0.1) . "% " . $sale->number . " сумма чека " . $sale->summ;
 
                 $userBonus = new UsersBonus;
                 $userBonus->tip = 'plus';
@@ -128,12 +128,53 @@ try {
                 if ($userBonus->getErrors()) {
                     $log .= json_encode($userBonus->getErrors(), JSON_UNESCAPED_UNICODE);
                 }
+                if ($credit_procent_index) {
+                    $back = round($sale->summ * 0.2);
+                    $nm = "Возврат с покупки " . (100 * 0.2) . "% " . $sale->number . " сумма чека " . $sale->summ;
+
+                    $userBonus = new UsersBonus;
+                    $userBonus->tip = 'plus';
+                    $userBonus->tip_sale = 'sale';
+                    $userBonus->date = $sale->date;
+                    $userBonus->date_start = date('Y-m-d H:i:s', strtotime('+1 day', strtotime($userBonus->date)));
+                    $userBonus->date_end = date('Y-m-d H:i:s', strtotime('+3 month', strtotime($userBonus->date)));
+                    $userBonus->phone = $phone;
+                    $userBonus->name = $nm;
+                    $userBonus->check_id = $sale->id;
+                    $userBonus->store_id =
+                    $userBonus->bonus = $back;
+                    $userBonus->site_id = 0;
+                    $userBonus->referal_id = 0;
+                    $userBonus->admin_id = $sale->admin_id;
+                    $userBonus->price = $sale->summ;
+                    $userBonus->store_id_1c = $sale->store_id_1c;
+                    $userBonus->seller_id_1c = $sale->seller_id;
+                    $userBonus->lid_id = $sale->order_id;
+                    $userBonus->save();
+                    if ($userBonus->getErrors()) {
+                        $log .= json_encode($userBonus->getErrors(), JSON_UNESCAPED_UNICODE);
+                    }
+                    if ($userFound->telegram_created_at == null) {
+                        $userFound->telegram_created_at = date("Y-m-d H:i:s");
+                        $userFound->save();
+                        if ($userFound->getErrors()) {
+                            $log .= json_encode(["error_id" => 5.3, "error" => $userFound->getErrors()]);
+                        }
+                    }
+
+                    $notifiableUser = new NotifiableUser;
+                    $notifiableUser->phone = $phone;
+                    $notifiableUser->type = "first_given_bonus";
+                    $notifiableUser->data = "" . ($back1 + $back);
+                    $notifiableUser->save();
+                }
             }
         }
 
         $info = ' ================ test Task ' . $taskNum . ' stop ================';
         echo $info;
         $log .= $info;
+        $log .= ' date >= ' . strtotime("-1 week", time());
         $dateTaskStop = date('Y-m-d H:i:s');
     } else {
         $info = '   Task ' . $taskNum . ' skip   ';
diff --git a/erp24/scripts/tasks/task_27_set_payroll_history.php b/erp24/scripts/tasks/task_27_set_payroll_history.php
new file mode 100755 (executable)
index 0000000..086fccb
--- /dev/null
@@ -0,0 +1,115 @@
+<?php
+
+/* @var $time integer */
+
+use yii_app\records\SchedulerTaskLog;
+use yii_app\services\AdminPayrollMonthInfoService;
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time_" . $time . "_time ";
+$taskNum = 27;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+
+try {
+    if (
+        (
+                (date('Gi', $time) == '0850'
+            &&
+                in_array(date('j', $time), range(6,11))
+        )
+            || $force
+        )
+        && $enable
+    ) {
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $dateFrom = date("Y-m-01", strtotime('-1 month'));
+        $dateTo = date("Y-m-t", strtotime('-1 month'));
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        $result = (new AdminPayrollMonthInfoService($dateFrom))->setAdminPayrollHistory();
+
+        $errorsCount = $result['errorsCount'];
+        $errors = $result['errors'];
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+            $error .= $valueErrors;
+        }
+
+        $infoText .= ' dateFrom = ' . $dateFrom . ' dateTo ' . $dateTo . 'errors count ' . $errorsCount;
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ' . $time . '  ' . date('Y-m-d H:i:s', $time). '  ' . date('Gi', $time);
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage() . ' >>> ' . $e->getLine();
+}
+
+
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
diff --git a/erp24/scripts/tasks/task_28_calculation_company_data_fot.php b/erp24/scripts/tasks/task_28_calculation_company_data_fot.php
new file mode 100644 (file)
index 0000000..e8b820c
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\metrics\FotMetrics;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 28;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0315';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+        )
+        && $enable
+    ) {
+
+
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $fotMetrics = new FotMetrics();
+        $fotMetrics->dateStart = $dateStart;
+        $fotMetrics->dateEnd = $dateEnd;
+
+        $startExecution = microtime( true );
+        $log .= $fotMetrics->insertData();
+        $timeExecution = sprintf( '%.6f sec.', microtime( true ) - $startExecution );
+
+        $log.= "\nВремя выполнения: $timeExecution\n";
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
diff --git a/erp24/scripts/tasks/task_29_calculation_company_data_write_offs.php b/erp24/scripts/tasks/task_29_calculation_company_data_write_offs.php
new file mode 100644 (file)
index 0000000..125ace0
--- /dev/null
@@ -0,0 +1,133 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\metrics\WriteOffsMetrics;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 29;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = true;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0415';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+
+        )
+        && $enable
+    ) {
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $writeOffsMetrics = new WriteOffsMetrics();
+        $writeOffsMetrics->dateStart = $dateStart;
+        $writeOffsMetrics->dateEnd = $dateEnd;
+
+        $startExecution = microtime( true );
+        $log .= $writeOffsMetrics->insertData();
+        $timeExecution = sprintf( '%.6f sec.', microtime( true ) - $startExecution );
+
+        $log.= "\nВремя выполнения: $timeExecution\n";
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
diff --git a/erp24/scripts/tasks/task_30_calculation_company_data_matrix_for_chart.php b/erp24/scripts/tasks/task_30_calculation_company_data_matrix_for_chart.php
new file mode 100644 (file)
index 0000000..bded16e
--- /dev/null
@@ -0,0 +1,123 @@
+<?php
+
+/**
+ * @var $time integer
+ */
+
+use yii_app\records\ChartDataSearch;
+use yii_app\records\SchedulerTask;
+use yii_app\records\SchedulerTaskLog;
+
+
+ini_set('max_execution_time', (string)(60 * 60 * 1)); // 1 час
+ini_set('display_errors', 'on');
+ini_set('display_errors', 1);
+ini_set('display_startup_errors', 1);
+error_reporting(E_ALL);
+
+echo "time2_" . $time . "_time2 ";
+$taskNum = 30;
+$dateTask = date('Y-m-d H:i:s');
+$dateTaskStart = null;
+$dateTaskStop = null;
+$log = '';
+$error = '';
+$infoError = '';
+$infoText = '';
+$description = '';
+$result = 0;
+
+$enable = false;
+$start = false;
+$force = false;
+
+$minuetTimeInTask = date('i', $time);
+$fullTimeInTask = date('Y-m-d H:i:s', $time);
+$time_start = '0345';
+try {
+    if (
+        (
+            date('Gi', $time) == $time_start
+            || $force
+        )
+        && $enable
+    ) {
+
+        $dateTaskStart = date('Y-m-d H:i:s');
+        $info = ' ================ test Task ' . $taskNum . ' start ================';
+        echo $info;
+        $log .= $info;
+        $log .= $time;
+
+        $schedulerTaskLog = new SchedulerTaskLog();
+        $schedulerTaskLog->setTaskNum($taskNum)
+            ->setName('Task ' . $taskNum)
+            ->setDate($dateTask)
+            ->setDateStart($dateTaskStart)
+        ;
+        $validate = $schedulerTaskLog->validate();
+        if ($validate) {
+            $schedulerTaskLog->save();
+        }
+
+        if (date('Y-m-02') == date('Y-m-d', strtotime('today'))) {
+            $dateStart = date('Y-m-d', strtotime('first day of previous month'));
+            $dateEnd = date('Y-m-01');
+        } else {
+            $dateStart = date('Y-m-d', strtotime('yesterday -1 day'));
+            $dateEnd = date('Y-m-d', strtotime('yesterday'));
+        }
+
+        $log .= ChartDataSearch::CalculationCompanyDataMatrixSalesForChartsDay($dateStart, $dateEnd);
+
+        $errorsCount = null;
+
+        if (!empty($errorsCount)) {
+            $infoError .= 'errors count ' . $errorsCount;
+            $error .= $infoError;
+//            $valueErrors = json_encode($errors,JSON_UNESCAPED_UNICODE);
+//            $error .= $valueErrors;
+        }
+
+
+
+
+        $info = ' ================ test Task ' . $taskNum . ' stop ================';
+        echo $info;
+        $log .= $info;
+        $log .= ' ' . $dateStart;
+        $log .= ' ' . $dateEnd;
+        $dateTaskStop = date('Y-m-d H:i:s');
+    } else {
+        $info = '   Task ' . $taskNum . ' skip   ';
+        echo $info;
+        $log .= $info;
+    }
+} catch (Exception $e) {
+    $error = 'Exception: ' . $e->getMessage() . ' ' . $e->getFile() . ' >>> ' . $e->getLine();
+}
+
+if (empty($schedulerTaskLog)) {
+    $schedulerTaskLog = new SchedulerTaskLog();
+    $schedulerTaskLog->setTaskNum($taskNum)
+        ->setName('Task ' . $taskNum)
+        ->setDate($dateTask)
+        ->setDateStart($dateTaskStart)
+        ->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+} else {
+    $schedulerTaskLog->setDateStop($dateTaskStop)
+        ->setDescription($description)
+        ->setError($error)
+        ->setInfo($infoText)
+        ->setLog($log)
+    ;
+}
+$validate = $schedulerTaskLog->validate();
+if ($validate) {
+    $schedulerTaskLog->save();
+}
\ No newline at end of file
index a7557ea4ee18ee15eff20a1c13517c4c2e0e2c39..9cf9f218d62b77b098e74085badaaf2954da4c7d 100644 (file)
 namespace yii_app\services;
 
 use yii\helpers\ArrayHelper;
-use yii_app\helpers\DateHelper;
 use yii_app\helpers\HtmlHelper;
 use yii_app\records\Admin;
 use yii_app\records\AdminGroup;
-use yii_app\records\AdminPayrollDays;
+use yii_app\records\AdminPayroll;
+use yii_app\records\AdminPayrollHistory;
 use yii_app\records\AdminPayrollMonthInfo;
 use yii_app\records\CityStore;
 use yii_app\records\EmployeePosition;
 
 class AdminPayrollMonthInfoService
 {
+    private $notInStoreIds;
+    private $yearSelect;
+    private $monthSelect;
+    private $monthWithZeroSelect;
+    private $dateFromBeginMonth;
+    private $dateToEndMonth;
+    private $dateTo;
+    private $dateFrom;
+    private $groupIds;
+    private $entityCityStore;
+    private $exportCityStore;
+    private $entityAdmin;
+    private $exportAdmin;
+    private $employeePosition;
+    private $employeeAdminGroup;
+    private $cityStoreNames;
+    private $monthNameSelect;
+    private $cabinetService;
+
+    public function __construct($dateFrom)
+    {
+        $this->cabinetService = new CabinetService();
+
+        $this->dateFrom = $dateFrom;
+        $this->notInStoreIds = Admin::NOT_IN_STORE_IDS;
+        $this->yearSelect = date("Y", strtotime($this->dateFrom));
+        $this->monthSelect = date("n", strtotime($this->dateFrom));
+        $this->monthWithZeroSelect = date("m", strtotime($this->dateFrom));
+        $this->dateFromBeginMonth = date("Y-m-01", strtotime($this->dateFrom));
+        $this->dateToEndMonth = date("Y-m-t", strtotime($this->dateFrom));
+        $this->dateTo = $this->dateToEndMonth;
+        if ($this->monthSelect == date("n")) {
+            $this->dateTo = date('Y-m-d', strtotime("-1 day"));
+        }
+        $this->groupIds = Admin::ADMIN_PAYROLL_MAKE_GROUP_IDS;
+        $this->employeePosition = EmployeePosition::getAllIdName();
+
+
+        $this->entityCityStore = ExportImportService::getEntityByType('city_store');
+        $this->exportCityStore = ArrayHelper::map($this->entityCityStore, 'entity_id', 'export_val');
+        $this->entityAdmin = ExportImportService::getEntityByType('admin');
+        $this->exportAdmin = ArrayHelper::map($this->entityAdmin, 'entity_id', 'export_val');
+        $this->employeePosition = EmployeePosition::getAllIdName();
+        $this->employeeAdminGroup = AdminGroup::getNames();
+        $this->cityStoreNames = CityStore::getNames();
+        $this->monthNameSelect = HtmlHelper::getMonthName($this->monthWithZeroSelect);
+    }
+
+    public function setAdminPayrollHistory()
+    {
+        AdminPayroll::clearPayrollFiredAdmin($this->yearSelect, $this->monthSelect);
+        AdminPayroll::clearPayrollWithoutShiftAdmin($this->yearSelect, $this->monthSelect);
+
+        $idsTimeTableArray = $this->cabinetService->getTimetableDataList($this->dateFrom, $this->dateTo);
+        $idsAdminTimeTable = ArrayHelper::getColumn($idsTimeTableArray, 'admin_id');
+
+        $admins = Admin::getAdmins(
+            $idsAdminTimeTable,
+            $this->groupIds,
+            'ASC',
+            null,
+            null,
+            $this->notInStoreIds,
+            true
+        );
+
+        $errors = [];
+        $adminInfo = [];
+
+        if (empty($admins)) {
+            $errors[] = 'admins is empty';
+        } else {
+            $packetNum = time();
+            $winStoreIdDayChallenge = [];
+
+            foreach ($admins as $employeeSelect) {
+                $employeeId = $employeeSelect['id'];
+                $controller = null;
+                $employeeGroupId = $employeeSelect['group_id'];
+
+                $isAdministrator = Admin::isAdministrator($employeeGroupId);
+                $ratingId = RatingService::getRatingId($employeeGroupId);
+
+                $payrollValues = $this->cabinetService->getDataDynamic202310(
+                    $employeeId,
+                    $employeeSelect,
+                    $employeeGroupId,
+                    $isAdministrator,
+                    $ratingId,
+                    $this->dateFrom,
+                    $this->dateTo,
+                    $controller,
+                    $winStoreIdDayChallenge,
+                    $this->exportCityStore,
+                    $this->exportAdmin,
+                    $this->yearSelect,
+                    $this->monthSelect,
+                    $this->monthWithZeroSelect,
+                    $this->monthNameSelect,
+                    $this->dateFromBeginMonth,
+                    $this->dateToEndMonth,
+                    $this->employeePosition,
+                    $this->employeeAdminGroup,
+                    $this->cityStoreNames
+                );
+
+                if (array_key_exists('errorText', $payrollValues)) {
+                    $errors[] = $errorRow = $payrollValues['errorText'];
+                    InfoLogService::setInfoLog(__FILE__, __LINE__, $error ?? [] , 'error  payrollHistoryValues');
+                } else {
+                    AdminPayrollHistory::setValues($payrollValues,
+                        $employeeId,
+                        $employeeSelect['store_id'],
+                        $this->yearSelect,
+                        $this->monthSelect,
+                        $packetNum
+                    );
+                }
+
+                $adminInfo[$employeeId] = $payrollValues;
+            }
+        }
+        return [
+            'errors' => $errors,
+            'errorsCount' => count($errors),
+            'adminInfo' => $adminInfo,
+        ];
+    }
     public static function setAdminPayrollMonth($dateFrom, $dateTo)
     {
 
index 050072018a914b08f6c9ab108e8dc661af55c8f1..440752346706dfc02df51b96f76d38f8108d79d5 100755 (executable)
@@ -4,6 +4,7 @@ namespace yii_app\services;
 
 use yii\helpers\ArrayHelper;
 use yii_app\helpers\DateHelper;
+use yii_app\records\Admin;
 use yii_app\records\AdminBonusConversion;
 use yii_app\records\AdminPayrollDays;
 use yii_app\records\CityStore;
@@ -871,6 +872,72 @@ class BonusService
         return $rateId;
 
     }
+
+    public function getAdminTeamPayrollTable($teamBonus) : array
+    {
+        $adminTeamPayroll = [];
+
+        // $teamBonusAdminPayDayAll
+        // key 893_2023-12-01
+        // value = sum;
+        $teamBonusAdminPayDayAll = ArrayHelper::getValue($teamBonus, 'adminPayDayAll');
+
+        // $teamBonusPayrollVariableDaysAll
+        // key 297_2023-12-07
+        // value = sum;
+        $teamBonusPayrollVariableDaysAll = ArrayHelper::getValue($teamBonus, 'payrollVariableDaysAll');
+
+        if (!empty($teamBonusAdminPayDayAll) && is_array($teamBonusAdminPayDayAll)) {
+            $arrayKeysAdminIdDate = array_unique(array_merge(array_keys($teamBonusAdminPayDayAll), array_keys($teamBonusPayrollVariableDaysAll)));
+        }
+        $adminIds = [];
+        $days = [];
+        if (!empty($arrayKeysAdminIdDate)) {
+            foreach ($arrayKeysAdminIdDate as $key => $row) {
+                $arrayRow = explode('_',$row);
+                $adminIdRow = $arrayRow[0];
+                $dateRow = $arrayRow[1];
+                $adminIds[] = $adminIdRow;
+                $days[] = $dateRow;
+            }
+        }
+
+        $adminIds = array_unique($adminIds);
+
+        $admins = Admin::getAdmins($adminIds, null, 'ASC');
+
+        $days = array_unique($days);
+
+        $result = [];
+        foreach ($admins as $admin) {
+            $result[$admin['id']]['admin_id'] = $admin['id'];
+            $result[$admin['id']]['admin_name'] = $admin['name'];
+            $result[$admin['id']]['group_name'] = $admin['group_name'];
+            $daysRow = [];
+
+            foreach ($days as $day) {
+                $keyAdminIdDateRow = $admin['id'] . '_' . $day;
+                $payConstantRow = 0;
+                if (array_key_exists($keyAdminIdDateRow, $teamBonusAdminPayDayAll)) {
+                    $payConstantRow = ArrayHelper::getValue($teamBonusAdminPayDayAll, $keyAdminIdDateRow);
+                }
+                $payVariableRow = 0;
+
+                if (array_key_exists($keyAdminIdDateRow, $teamBonusPayrollVariableDaysAll)) {
+                    $payVariableRow = ArrayHelper::getValue($teamBonusPayrollVariableDaysAll, $keyAdminIdDateRow);
+                }
+                $daysRow[$day] = [
+                    'pay_constant' => $payConstantRow,
+                    'pay_variable' => $payVariableRow,
+                ];
+            }
+            ksort($daysRow);
+
+            $result[$admin['id']]['days'] = $daysRow;
+        }
+
+        return $result;
+    }
     /**
      * @param array $normaSmena
      * @param $summ
@@ -878,7 +945,26 @@ class BonusService
      */
     public function getTeamBonus($adminId, $storeId, $storeGuid, $dateFrom, $dateTo): array
     {
-        $result = [];
+        $percentTeamBonusInMonth = self::getPercentTeamBonusInMonth($storeId, $dateFrom);
+
+        $result = [
+            'adminStoreFotStableSum' => 0,
+            'adminStoreFotVariableSum' => 0,
+            'adminStoreFotSum' => 0,
+            'writeOffsSum' => 0,
+            'fotStoreAndWriteOff' => 0,
+            'salesByStore' => 0,
+            'salesByStorePart' => 0,
+            'primeFondStore' => 0,
+            'shiftCountAll' => 0,
+            'primeFondStoreOneShift' => 0,
+            'personShiftCount' => 0,
+            'personPrimeFondStore' => 0,
+            'adminStoreFotSumPercent' => 0,
+            'writeOffsSumPercent' => 0,
+            'adminStoreFotAndWriteOffsSumPercent' => 0,
+            'percentTeamBonusInMonth' => $percentTeamBonusInMonth,
+        ];
 
         $slotTypeId = [
             Timetable::TIMESLOT_WORK, // "работа"
@@ -894,10 +980,14 @@ class BonusService
             ->all();
 
         $adminTimetable = [];
+        $adminTimetableSalaryShift = [];
 
         if (!empty($timeTable)){
             foreach ($timeTable as $row) {
                 $adminTimetable[$row['admin_id']][] = $row['date'];
+                if (!empty($row['salary_shift'])) {
+                    $adminTimetableSalaryShift[$row['admin_id']][$row['date']] = $row['salary_shift'];
+                }
 
             }
 
@@ -929,7 +1019,16 @@ class BonusService
                         $adminTimetableRow = $adminTimetable[$adminId];
                         foreach ($dates as $date) {
                             if (in_array($date, $adminTimetableRow)) {
-                                $adminPayDayRow = EmployeePayment::getSalary($adminId, $date, $adminPayDayDict);
+                                if (
+                                    array_key_exists($adminId, $adminTimetableSalaryShift)
+                                    &&
+                                    array_key_exists($date, $adminTimetableSalaryShift[$adminId])
+                                ) {
+                                    $adminPayDayRow = $adminTimetableSalaryShift[$adminId][$date];
+                                } else {
+                                    $adminPayDayRow = EmployeePayment::getSalary($adminId, $date, $adminPayDayDict);
+                                }
+
                                 $keyAdminPayDayDictAllRow = $adminId . '_' . $date;
                                 $adminPayDayAll[$keyAdminPayDayDictAllRow] = $adminPayDayRow;
                                 $adminPayDay[$adminId][$date] = $adminPayDayRow;
@@ -1004,7 +1103,7 @@ class BonusService
 //        echo '<br>';
 
                 $salesByStore = (new CabinetService())->getSalesSaleSum($dateFrom, $dateTo, $storeGuid);
-                $percentTeamBonusInMonth = self::getPercentTeamBonusInMonth($storeId, $dateFrom);
+
                 $percentCoefficient = $percentTeamBonusInMonth / 100;
                 $salesByStorePart = $salesByStore * $percentCoefficient;
 
@@ -1062,6 +1161,9 @@ class BonusService
                     'writeOffsSumPercent' => $writeOffsSumPercent,
                     'adminStoreFotAndWriteOffsSumPercent' => $adminStoreFotAndWriteOffsSumPercent,
                     'percentTeamBonusInMonth' => $percentTeamBonusInMonth,
+                    'days' => $dates,
+                    'adminPayDayAll' => $adminPayDayAll,
+                    'payrollVariableDaysAll' => $payrollVariableDaysAll,
                 ];
             }
         }
@@ -1070,19 +1172,20 @@ class BonusService
 
     }
 
-    public static function getPercentTeamBonusInMonth($storeId, $dateFrom)
+    public static function getPercentTeamBonusInMonth($storeId, $dateFrom) : int
     {
-        $percentDefault = 20;
-        $year = date("Y" , strtotime($dateFrom));
-        $month = date("m" , strtotime($dateFrom));
+        $percentDefault = 0;
+        $year = (int) date("Y" , strtotime($dateFrom));
+        $month = (int) date("n" , strtotime($dateFrom));
         $percentPrepared = TeambonusSettings::find()
             ->select(['procent'])
             ->andWhere(['store_id' => $storeId])
             ->andWhere(['year' => $year])
             ->andWhere(['month' => $month])
+            ->orderBy(['created_at' => SORT_DESC])
             ->scalar();
 
-        $percent = (!empty($percentPrepared)) ? $percentPrepared : $percentDefault;
+        $percent = (isset($percentPrepared)) ? $percentPrepared : $percentDefault;
 
         return $percent;
     }
index c433d29c7ee6ac553b19a716395d0e6dc2b21361..d38629178d3cfef5a1bf76ca35dd56b16b3fe563 100755 (executable)
@@ -155,6 +155,12 @@ class CabinetService
             33, // Должанская 33/11
             29, // ул. Страж Революции, 1А
         ],
+        '2023-11' => [
+            37, // Тимирязева 9к2
+        ],
+        '2023-12' => [
+            37, // Тимирязева 9к2
+        ],
     ];
     /**
      * Расчет демотивации Год к Году заблокирован на указанный месяц
@@ -563,7 +569,7 @@ class CabinetService
         $cityStoreNames,
         bool $calculatePersonalRating = true
     )
-    {
+    { //getDataDynamic
 
         if (!empty($employeeSelect['store_id'])) {
             $employeeSelectStoreId = $employeeSelect['store_id'];
@@ -2081,7 +2087,7 @@ class CabinetService
         $cityStoreNames,
         bool $calculatePersonalRating = true
     )
-    {
+    { // getDataDynamic202310
 
         if (!empty($employeeSelect['store_id'])) {
             $employeeSelectStoreId = $employeeSelect['store_id'];
@@ -2368,12 +2374,28 @@ class CabinetService
         $normalCountShiftArray = SalaryHelper::$normalCountShift;
         if (!empty($employeeSelect["group_id"])) {
             if (Admin::ADMINISTRATOR_GROUP_ID == $employeeSelect["group_id"]){
-                // у Администратора число смен равно количеству рабочих дней в месяце
-                $normalCountShift = HtmlHelper::getWorkDays($monthSelect, $yearSelect);
-
+                if ($dateFrom >= '2023-12-01') {
+                    $dayMonthDateRow = $yearSelect . '-' . $monthSelect . '-01';
+                    $timeRow = strtotime($dayMonthDateRow);
+                    $monthSelectRow = date('n', $timeRow);
+                    $yearSelectRow = date('Y', $timeRow);
+                    if ($yearSelectRow == '2024' && $monthSelectRow == 1) {
+                        $normalCountShift = 20;
+                    } else {
+                        // у Администратора число смен равно количеству дней со вторника по субботу в месяце
+                        $normalCountShift = HtmlHelper::getAdministratorWorkDays($monthSelect, $yearSelect);
+                    }
+                } else {
+                    // у Администратора число смен равно количеству рабочих дней в месяце
+                    $normalCountShift = HtmlHelper::getWorkDays($monthSelect, $yearSelect);
+                }
             } else {
                 $employeeSelectGroupId = $this->getGroupId($employeeId, $employeeSelect['group_id'], $dateFrom, $dateTo);
-                $normalCountShift = $normalCountShiftArray[$employeeSelectGroupId];
+                if (array_key_exists($employeeSelectGroupId, $normalCountShiftArray)) {
+                    $normalCountShift = $normalCountShiftArray[$employeeSelectGroupId];
+                } else {
+                    $normalCountShift = 15;
+                }
             }
         }
 
@@ -2435,7 +2457,7 @@ class CabinetService
             $planMonthCalculate = round($salaryAdministratorByDay * $normalCountShiftValue, 1);
             $planMonthCalculatePercent = round(100 * $planMonthCalculate /$planMonthAdministrator,1);
 
-            $administratorOklad = $this->bonusService->getAdministratorOklad($planMonthCalculate);
+            $administratorOklad = $this->getAdministratorSalaryShift($employeeId, $dateFrom, $planMonthCalculate);
         }
 
         $saleByMonthCalculate = 0;
@@ -2462,11 +2484,11 @@ class CabinetService
             }
 
             if ($isAdministrator) {
-                $administratorOklad = $this->bonusService->getAdministratorOklad($saleByMonthCalculate);
+                $administratorOklad = $this->getAdministratorSalaryShift($employeeId, $dateFrom, $saleByMonthCalculate);
             }
 
         } elseif ($isAdministrator && !empty($salesByStore)) {
-            $administratorOklad = $this->bonusService->getAdministratorOklad($salesByStore);
+            $administratorOklad = $this->getAdministratorSalaryShift($employeeId, $dateFrom, $salesByStore);
 
             $showBlockForecast = true;
 
@@ -2476,16 +2498,22 @@ class CabinetService
         }
 
 
+        $hourPayment = 10; //default value
+
         if (!empty($normalCountShift)) {
             if ($isAdministrator) {
                 $normalCostShift = round($administratorOklad / $normalCountShift, 1);
 
                 $dailyPayment = $normalCostShift;
+                $hourPayment = $dailyPayment / Admin::SHIFT_HOUR_COUNT_ADMINISTRATOR;
+
 
             } else {
                 $normalCostShift = round($monthlySalary['monthly_salary'] / $normalCountShift, 1);
 
                 $dailyPayment = $monthlySalary['daily_payment'];
+
+                $hourPayment = $dailyPayment / Admin::SHIFT_HOUR_COUNT_FLORIST;
             }
         }
 
@@ -2547,10 +2575,15 @@ class CabinetService
         $bonusByConvertionPercent = $this->bonusService->getBonusByConvertionPercent($conversionPercent, $employeeSelectStoreId, $dateFrom, $dateTo);
 
         $timetableAdmin = [];
+        $partTimeWagesSumAdminStore = 0;
+        $partTimeWagesCountAdminStore = 0;
 
         if (!empty($timetable)) {
             if (!empty($storeAdminsGuids)) {
-                $timetableAdmin = $this->getTimetableDate($timetable, $employeeId, $adminGuid, $storeAdminsGuids, $dateFrom, $dateTo, $normalCostShift, $isAdministrator, $entityCityStoreEmployeeSelect);
+                $timetableAdminValues = $this->getTimetableDate($timetable, $employeeId, $adminGuid, $storeAdminsGuids, $dateFrom, $dateTo, $normalCostShift, $isAdministrator, $entityCityStoreEmployeeSelect);
+                $timetableAdmin = ArrayHelper::getValue($timetableAdminValues, 'timetable');
+                $partTimeWagesSumAdminStore = ArrayHelper::getValue($timetableAdminValues, 'partTimeWagesSum');
+                $partTimeWagesCountAdminStore = ArrayHelper::getValue($timetableAdminValues, 'partTimeWagesCount');
             } else {
                 $errorText = 'У сотрудника "' . $employeeSelect['name_full'] . '" <br>';
                 $errorText .= 'за выбранный интервал с ' . $dateFrom . '  по  ' . $dateTo . ' <br>';
@@ -2569,11 +2602,19 @@ class CabinetService
             $timetableAdminTypeFirstShift = $timetableAdmin[array_key_first($timetableAdmin)]['typeSmenaInt'];
         }
 
-        if (!empty($timetableAnotherStore)) {
-            $timetableAdminAnotherStore = $this->getTimetableDate($timetableAnotherStore, $employeeId, $adminGuid, $anotherStoreAdminsGuids, $dateFrom, $dateTo, $normalCostShift, $isAdministrator);
+        $partTimeWagesSumAdminAnotherStore = 0;
+        $partTimeWagesCountAdminAnotherStore = 0;
 
+        if (!empty($timetableAnotherStore)) {
+            $timetableAdminAnotherStoreValues = $this->getTimetableDate($timetableAnotherStore, $employeeId, $adminGuid, $anotherStoreAdminsGuids, $dateFrom, $dateTo, $normalCostShift, $isAdministrator);
+            $timetableAdminAnotherStore = ArrayHelper::getValue($timetableAdminAnotherStoreValues, 'timetable');
+            $partTimeWagesSumAdminAnotherStore = ArrayHelper::getValue($timetableAdminAnotherStoreValues, 'partTimeWagesSum');
+            $partTimeWagesCountAdminAnotherStore = ArrayHelper::getValue($timetableAdminAnotherStoreValues, 'partTimeWagesCount');
         }
 
+        $partTimeWagesSumAdminAllStore = $partTimeWagesSumAdminStore + $partTimeWagesSumAdminAnotherStore;
+        $partTimeWagesCountAdminAllStore = $partTimeWagesCountAdminStore + $partTimeWagesCountAdminAnotherStore;
+
         if ($allowedConversionCalculate) {
             $conversionDayAdministrator = $this->getSumListConversion($employeeSelectStoreId, $dateFromConversion, $dateTo);
             $conversionShift = $this->getConversionShift($dateFromConversion, $dateTo, $employeeSelectStoreId);
@@ -2684,10 +2725,17 @@ class CabinetService
         $personBonuses = ArrayHelper::getValue($personBonusesArray, 'bonuses'); // Персональная премия
         $personColorRubleBonuses = ArrayHelper::getValue($personBonusesArray, 'color_ruble_bonuses'); // Персональная премия
         $personRetention = ArrayHelper::getValue($personBonusesArray, 'retention'); // Персональный вычет
+        $personRetentionСomment = 'Персональный вычет';
+        $personRetentionСommentText = ArrayHelper::getValue($personBonusesArray, 'retention_comment'); // Комментарий персонального вычета
+        if (!empty($personRetentionСommentText)) {
+            $personRetentionСomment = $personRetentionСommentText;
+        }
         $personPrepaidExpense = ArrayHelper::getValue($personBonusesArray, 'prepaid_expense'); // Аванс
         $personCounting = ArrayHelper::getValue($personBonusesArray, 'counting'); // Подсчёт
         $personVacationDay = ArrayHelper::getValue($personBonusesArray, 'vacation_day'); // Оплаченный отпуск
         $personVacationPay = $personVacationDay * $normalCostShift;//Стоимость одной смены
+        $personPartTimeJobHours = ArrayHelper::getValue($personBonusesArray, 'part_time_job_hours'); // Подработки в часах
+        $personPartTimeJobHoursPay = $personPartTimeJobHours * $hourPayment; // Стоимость подработки по часам в рублях
 
         $possibleSumGameBonusValuesFlorist = [];
 
@@ -2717,6 +2765,25 @@ class CabinetService
         $allSumGameBonusValues = $allPossibleSumGameBonusValuesFlorist + $personSumColorRubleBonusesValues;
 
 
+        // Командный бонус
+        $teamBonus = $this->bonusService->getTeamBonus( $employeeId, $employeeSelectStoreId, $entityCityStoreEmployeeSelect, $dateFrom, $dateToEndMonth);
+        $teamBonusDetail = json_encode($teamBonus,JSON_UNESCAPED_UNICODE);
+        $teamBonusValuePrepared = ArrayHelper::getValue($teamBonus, 'personPrimeFondStore');
+        $teamBonusValue = ($teamBonusValuePrepared > 0) ? $teamBonusValuePrepared : 0;
+
+        $adminTeamPayrollTable = [];
+        if (!empty($teamBonus) && $isAdministrator) {
+            $adminTeamPayrollTable = $this->bonusService->getAdminTeamPayrollTable($teamBonus);
+        }
+
+        // Премия за процент качества
+        $userQualityPercent = 0; // % качества
+
+        $userQualityPercentPrepared = QualityRating::getQualityRating($employeeId, $dateTo);
+        if (!empty($userQualityPercentPrepared)) {
+            $userQualityPercent = $userQualityPercentPrepared;
+        }
+        $userQualityPremium = $this->bonusService->getBonusForQuality($userQualityPercent);
 
 
         $arrayTypes = ["wrap", "potted", "related","services","salut","other_items"];
@@ -2726,173 +2793,172 @@ class CabinetService
         $this->arr = [$adminGuid];
         $adminGuidArr = $this->arr;
 
-        if (!empty($arrayProducts["services"])) {
-            $arrUsersSalaryServicesPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["services"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator);
-            $arrUsersSalaryServices = ArrayHelper::getColumn($arrUsersSalaryServicesPrepared, 'bonus');
-            $arrUsersSalaryServicesCheck = ArrayHelper::getColumn($arrUsersSalaryServicesPrepared, 'check');
-        }
-        if (!empty($arrayProducts["related"])) {
-            $arrUsersSalaryRelatedPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["related"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator);
-            $arrUsersSalaryRelated = ArrayHelper::getColumn($arrUsersSalaryRelatedPrepared, 'bonus');
-            $arrUsersSalaryRelatedCheck = ArrayHelper::getColumn($arrUsersSalaryRelatedPrepared, 'check');
-        }
-        if (!empty($arrayProducts["potted"])) {
-            $arrUsersSalaryPottedPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["potted"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator);
-            $arrUsersSalaryPotted = ArrayHelper::getColumn($arrUsersSalaryPottedPrepared, 'bonus');
-            $arrUsersSalaryPottedCheck = ArrayHelper::getColumn($arrUsersSalaryPottedPrepared, 'check');
-        }
-        if (!empty($arrayProducts["wrap"])) {
-            $arrUsersSalaryWrapPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["wrap"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator);
-            $arrUsersSalaryWrap = ArrayHelper::getColumn($arrUsersSalaryWrapPrepared, 'bonus');
-            $arrUsersSalaryWrapCheck = ArrayHelper::getColumn($arrUsersSalaryWrapPrepared, 'check');
-        }
-        if (!empty($arrayProducts["other_items"])) {
-            $arrUsersSalaryOtherItemsPrepared = SalaryHelper::getSalaryBonusMulty($arrayProducts["other_items"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator);
-            $arrUsersSalaryOtherItems = ArrayHelper::getColumn($arrUsersSalaryOtherItemsPrepared, 'bonus');
-            $arrUsersSalaryOtherItemsCheck = ArrayHelper::getColumn($arrUsersSalaryOtherItemsPrepared, 'check');
-        }
-        if (!empty($arrayProducts["salut"])) {
-//            $dateFromToSalutArray = $this->salesService->getAllowedStart($dateFrom, $dateTo, SalesService::$allowedCalculateBonusForSalut);
+        /**/
+        $showHolidayVersion  = HolidayService::getHolidayVersionShow($dateFrom, $dateTo);
+//        $showHolidayVersion = false;
+        /**/
 
-            $arrUsersSalarySalutPrepared = SalaryHelper::getSalaryBonusSalut($arrayProducts["salut"], $adminGuidArr,  $dateFrom,  $dateTo, $exportAdmin, $isAdministrator, $employeeSelectStoreId);
-            $arrUsersSalarySalut = ArrayHelper::getColumn($arrUsersSalarySalutPrepared, 'bonus');
-            $arrUsersSalarySalutCheck = ArrayHelper::getColumn($arrUsersSalarySalutPrepared, 'check');
+        $arrResSalariesByFocusGroup = SalaryHelper::getSalariesByFocusGroup(
+            $employeeId,
+            $adminGuid,
+            $arrayProducts,
+            $adminGuidArr,
+            $dateFrom,
+            $dateTo,
+            $exportAdmin,
+            $isAdministrator,
+            $employeeSelectStoreId,
+            $showHolidayVersion
+        );
 
-        }
+        $arrUsersSalary = ArrayHelper::getValue($arrResSalariesByFocusGroup, 'arrUsersSalary');
+        $arrUsersSalaryCheck = ArrayHelper::getValue($arrResSalariesByFocusGroup, 'arrUsersSalaryCheck');
 
-        $arrUsersSalary = [
-            "services" => $arrUsersSalaryServices ?? [],
-            "related" => $arrUsersSalaryRelated ?? [],
-            "potted" => $arrUsersSalaryPotted ?? [],
-            "wrap" => $arrUsersSalaryWrap ?? [],
-            "salut" => $arrUsersSalarySalut ?? [],
-            "other_items" => $arrUsersSalaryOtherItems ?? [],
-        ];
+        $premiumByFocusGroups = $this->getPremiumByFocusGroups($adminGuid, $arrUsersSalary,  $dateFrom,  $dateTo, $isAdministrator);
 
-        $arrUsersSalaryCheck = [
-            "services" => $arrUsersSalaryServicesCheck[$adminGuid] ?? [],
-            "related" => $arrUsersSalaryRelatedCheck[$adminGuid] ?? [],
-            "potted" => $arrUsersSalaryPottedCheck[$adminGuid] ?? [],
-            "wrap" => $arrUsersSalaryWrapCheck[$adminGuid] ?? [],
-            "salut" => $arrUsersSalarySalutCheck[$adminGuid] ?? [],
-            "other_items" => $arrUsersSalaryOtherItemsCheck[$adminGuid] ?? [],
-        ];
+        $userSalaryServices = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryServices');
+        $userSalaryServicesPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryServicesPremium');
 
-        $userSalaryServices = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["services"])) {
-            $userSalaryServices = ($arrUsersSalary["services"][$adminGuid] > 0) ? $arrUsersSalary["services"][$adminGuid] : 0;
-        }// услуги
+        $userSalaryRelated = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryRelated');
+        $userSalaryRelatedPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryRelatedPremium');
 
-        $userSalaryRelated = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["related"])) {
-            $userSalaryRelated = ($arrUsersSalary["related"][$adminGuid] > 0) ? $arrUsersSalary["related"][$adminGuid] : 0; // сопутка
-        }
+        $userSalaryPotted = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryPotted');
+        $userSalaryPottedPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryPottedPremium');
 
-        $userSalaryPotted = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["potted"])) {
-            $userSalaryPotted = ($arrUsersSalary["potted"][$adminGuid] > 0) ? $arrUsersSalary["potted"][$adminGuid] : 0; // горшечка
-        }
+        $userSalaryWrap = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryWrap');
+        $userSalaryWrapPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryWrapPremium');
 
-        $userSalaryWrap = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["wrap"])) {
-            $userSalaryWrap = ($arrUsersSalary["wrap"][$adminGuid] > 0) ? $arrUsersSalary["wrap"][$adminGuid] : 0; // упаковка
-        }
+        $userSalarySalut = ArrayHelper::getValue($premiumByFocusGroups, 'userSalarySalut');
+        $userSalarySalutPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalarySalutPremium');
 
-        $userSalarySalut = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["salut"])) {
-            $userSalarySalut = ($arrUsersSalary["salut"][$adminGuid] > 0) ? $arrUsersSalary["salut"][$adminGuid] : 0; // пиротехника
-        }
+        $userSalaryOtherItems = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryOtherItems');
+        $userSalaryOtherItemsPremium = ArrayHelper::getValue($premiumByFocusGroups, 'userSalaryOtherItemsPremium');
 
-        $userSalaryOtherItems = 0;
-        if (array_key_exists($adminGuid, $arrUsersSalary["other_items"])) {
-            $userSalaryOtherItems = ($arrUsersSalary["other_items"][$adminGuid] > 0) ? $arrUsersSalary["other_items"][$adminGuid] : 0; // Другие товары
-        }
+        $premiumByMatrix = $this->getPremiumByMatrix(
+            $employeeSelectStoreId,
+            $adminGuid,
+            $dateFrom,
+            $dateTo,
+            $isAdministrator,
+            $showHolidayVersion
+        );
 
-        $userQualityPercent = 0; // % качества
+        $salesMatrix = ArrayHelper::getValue($premiumByMatrix, 'salesMatrix');
+        $salaryMatrix = ArrayHelper::getValue($premiumByMatrix, 'salaryMatrix');
+        $salaryMakeMatrix = ArrayHelper::getValue($premiumByMatrix, 'salaryMakeMatrix');
+        $bonusSalaryMatrix = ArrayHelper::getValue($premiumByMatrix, 'bonusSalaryMatrix');
+        $makeMatrix = ArrayHelper::getValue($premiumByMatrix, 'makeMatrix');
+        $bonusMakeMatrix = ArrayHelper::getValue($premiumByMatrix, 'bonusMakeMatrix');
+        $matrixPrime = ArrayHelper::getValue($premiumByMatrix, 'matrixPrime');
 
-        $userQualityPercentPrepared = QualityRating::getQualityRating($employeeId, $dateTo);
-        if (!empty($userQualityPercentPrepared)) {
-            $userQualityPercent = $userQualityPercentPrepared;
-        }
-        $userQualityPremium = $this->bonusService->getBonusForQuality($userQualityPercent);
+        $consolidatedPremiumByStore = 0;
 
+        $onePartHolidayPremium = 0;
+        $adminsHolidayShiftCount = 0;
+        $personPremiumByStore = 0;
 
-        $teamBonus = $this->bonusService->getTeamBonus( $employeeId, $employeeSelectStoreId, $entityCityStoreEmployeeSelect, $dateFrom, $dateToEndMonth);
-        $teamBonusValuePrepared = ArrayHelper::getValue($teamBonus, 'personPrimeFondStore');
-        $teamBonusValue = ($teamBonusValuePrepared > 0) ? $teamBonusValuePrepared : 0;
+        $onePartHolidayPremium = 0;
+        $personHolidayShiftCount = 0;
 
-        $userSalaryServicesPremium = round($userSalaryServices * 0.1); // 10% за продажу услуг
-        $userSalaryRelatedPremium = round($userSalaryRelated * 0.05); // 5% за личные продажи сопутки
-        $userSalaryPottedPremium = round($userSalaryPotted * 0.05);
-        $userSalaryWrapPremium = round($userSalaryWrap * 0.05); // 5% за личные продажи упаковки
+        if ($showHolidayVersion) {
+            // Премирование на праздники
+            $consolidatedArrResSalariesByFocusGroup = SalaryHelper::getSalariesByFocusGroup(
+                $employeeId,
+                $adminGuid,
+                $arrayProducts,
+                $adminGuidArr,
+                $dateFrom,
+                $dateTo,
+                $exportAdmin,
+                $isAdministrator,
+                $employeeSelectStoreId,
+                $showHolidayVersion,
+false
+            );
 
-        $userSalarySalutPremium  = round($userSalarySalut * 0.05); // 5% за личные продажи пиротехники
+            $consolidatedArrUsersSalary = ArrayHelper::getValue($consolidatedArrResSalariesByFocusGroup, 'arrUsersSalary');
+            $consolidatedArrUsersSalaryCheck = ArrayHelper::getValue($consolidatedArrResSalariesByFocusGroup, 'arrUsersSalaryCheck');
+            $consolidatedAdminGuidDateArrByFocusGroup = ArrayHelper::getValue($consolidatedArrResSalariesByFocusGroup, 'adminGuidDateArrByFocusGroup');
 
-        $userSalaryOtherItemsPremium  = round($userSalaryOtherItems * 0.01); // 1% за личные продажи не фокусной продукции (Другме товары)
 
-        //Букеты по матрице
+            $consolidatedPremiumByFocusGroups = $this->getPremiumByFocusGroups($adminGuid, $consolidatedArrUsersSalary,  $dateFrom,  $dateTo, $isAdministrator);
 
-        $salesMatrix = $this->salesService->getMatrixSalesProducts($adminGuid,  $dateFrom,  $dateTo, $isAdministrator);
+            $consolidatedUserSalaryServices = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryServices');
+            $consolidatedUserSalaryServicesPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryServicesPremium');
 
-        $salesMatrixProductGuids = ArrayHelper::getColumn($salesMatrix, 'product_guid');
-        $salesMatrixProducts = Products1c::getProducts1cByType('products', $salesMatrixProductGuids);
-        $salesMatrixProductNames = ArrayHelper::map($salesMatrixProducts, 'id','name');
+            $consolidatedUserSalaryRelated = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryRelated');
+            $consolidatedUserSalaryRelatedPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryRelatedPremium');
 
-        $salaryMatrix = 0;
-        $bonusSalaryMatrix = 0;
-        $salesMatrixTemp = $salesMatrix;
-        foreach ($salesMatrixTemp as $keySalesMatrix => $row) {
-            $matrixBonusCoefficientRow = $this->bonusService->getMatrixBonusCoefficient($row['date']);
-            $rowBonus = $row["summ"] * $matrixBonusCoefficientRow;
-            $salesMatrix[$keySalesMatrix]["bonus"] = $rowBonus;
-            if($row["operation"] == Sales::OPERATION_SALE) {
-                $salaryMatrix += $row["summ"];
-                $bonusSalaryMatrix += $rowBonus;
-            } elseif($row["operation"] == Sales::OPERATION_RETURN) {
-                $salaryMatrix -= $row["summ"];
-                $bonusSalaryMatrix -= $rowBonus;
-            }
-            $productNameRow = '';
-            if (array_key_exists($row["product_guid"], $salesMatrixProductNames)) {
-                $productNameRow = ArrayHelper::getValue($salesMatrixProductNames, $row["product_guid"]);
-            }
-            $salesMatrix[$keySalesMatrix]["product_name"] = $productNameRow;
-        }
+            $consolidatedUserSalaryPotted = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryPotted');
+            $consolidatedUserSalaryPottedPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryPottedPremium');
 
-        $bonusSalaryMatrix = round($bonusSalaryMatrix);
+            $consolidatedUserSalaryWrap = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryWrap');
+            $consolidatedUserSalaryWrapPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryWrapPremium');
 
-        $makeMatrix = $this->salesService->getMatrixMakeProducts($adminGuid,  $dateFrom,  $dateTo, $isAdministrator);
+            $consolidatedUserSalarySalut = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalarySalut');
+            $consolidatedUserSalarySalutPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalarySalutPremium');
 
-        $makeMatrixProductGuids = ArrayHelper::getColumn($makeMatrix, 'product_guid');
-        $makeMatrixProducts = Products1c::getProducts1cByType('products', $makeMatrixProductGuids);
-        $makeMatrixProductNames = ArrayHelper::map($makeMatrixProducts, 'id','name');
+            $consolidatedUserSalaryOtherItems = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryOtherItems');
+            $consolidatedUserSalaryOtherItemsPremium = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryOtherItemsPremium');
 
-        $salaryMakeMatrix = 0;
-        $bonusMakeMatrix = 0;
-        $makeMatrixTemp = $makeMatrix;
-        foreach ($makeMatrixTemp as $kayMakeMatrix => $row) {
-            $matrixBonusCoefficientRow = $this->bonusService->getMatrixBonusCoefficient($row['date']);
-            $rowBonus = $row["summ"] * $matrixBonusCoefficientRow;
-            $makeMatrix[$kayMakeMatrix]["bonus"] = $rowBonus;
-            if($row["operation"] == Sales::OPERATION_SALE) {
-                $salaryMakeMatrix += $row["summ"];
-                $bonusMakeMatrix += $rowBonus;
-            } elseif($row["operation"] == Sales::OPERATION_RETURN) {
-                $salaryMakeMatrix -= $row["summ"];
-                $bonusMakeMatrix -= $rowBonus;
+            $consolidatedUserSalaryPremiumSum = ArrayHelper::getValue($consolidatedPremiumByFocusGroups, 'userSalaryPremiumSum');
+
+
+
+            $adminGuidNames = Admin::getAdminGuidNames();
+
+            $consolidatedArrUsersSalaryCheckTmp = $consolidatedArrUsersSalaryCheck;
+            foreach ($consolidatedArrUsersSalaryCheckTmp as $key => $rows) {
+                foreach ($rows as $keyInner => $item) {
+                    $consolidatedArrUsersSalaryCheck[$key][$keyInner]['name'] = $adminGuidNames[$item['seller_id']] ?? $item['seller_id'];
+                }
             }
 
-            $productNameRow = '';
-            if (array_key_exists($row["product_guid"], $makeMatrixProductNames)) {
-                $productNameRow = ArrayHelper::getValue($makeMatrixProductNames, $row["product_guid"]);
+            // Премия за матрицу в праздники
+
+            $consolidatedPremiumByMatrix = $this->getPremiumByMatrix(
+                $employeeSelectStoreId,
+                $adminGuid,
+                $dateFrom,
+                $dateTo,
+                $isAdministrator,
+                $showHolidayVersion,
+                false
+            );
+
+            $consolidatedSalesMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'salesMatrix');
+            $consolidatedSalaryMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'salaryMatrix');
+            $consolidatedSalaryMakeMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'salaryMakeMatrix');
+            $consolidatedBonusSalaryMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'bonusSalaryMatrix');
+            $consolidatedMakeMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'makeMatrix');
+            $consolidatedBonusMakeMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'bonusMakeMatrix');
+            $consolidatedMatrixPrime = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'matrixPrime');
+            $consolidatedAdminGuidDateArrByMatrix = ArrayHelper::getValue($consolidatedPremiumByMatrix, 'adminGuidDateArrByMatrix');
+
+            $consolidatedPremiumByStore = $consolidatedMatrixPrime + $consolidatedUserSalaryPremiumSum;
+
+            $shiftCount = [];
+            $countByUser = [];
+
+            foreach ($consolidatedAdminGuidDateArrByFocusGroup as $subKey => $users) {
+                $shiftCount[] = count($users);
+                foreach ($users as $user) {
+                    if (array_key_exists($user, $countByUser)){
+                        ++$countByUser[$user];
+                    } else {
+                        $countByUser[$user] = 1;
+                    }
+                }
             }
-            $makeMatrix[$kayMakeMatrix]["product_name"] = $productNameRow;
-        }
 
-        $bonusMakeMatrix = round($bonusMakeMatrix);
+            $adminsHolidayShiftCount = array_sum($shiftCount) ;
+            $personHolidayShiftCount =  $countByUser[$adminGuid] ?? 0;
+            if (!empty($adminsHolidayShiftCount)) {
+                $onePartHolidayPremium = $consolidatedPremiumByStore / $adminsHolidayShiftCount;
+            }
+            $personPremiumByStore = $onePartHolidayPremium * $personHolidayShiftCount;
 
-        // итого: премия с матрицы
-        $matrixPrime = $bonusSalaryMatrix + $bonusMakeMatrix;
+        }
 
         $wagesBonusNormaSmenaAnotherStore = [];
         if (!empty($timetableAdminAnotherStoreById)) {
@@ -2955,6 +3021,13 @@ class CabinetService
                 $arrayColumnWages = array_merge($arrayColumnWages, $personBonusesArrayInfo);
             }
 
+            if (!empty($personPartTimeJobHoursPay)) {
+                $personBonusesArrayInfo = [
+                    'Оплата подработок по часам' . ' ('. $personPartTimeJobHours . '*' . $hourPayment . ' руб/час из оклада)' => (int) $personPartTimeJobHoursPay,
+                ];
+                $arrayColumnWages = array_merge($arrayColumnWages, $personBonusesArrayInfo);
+            }
+
             if (!empty($personVacationPay)) {
                 $personBonusesArrayInfo = [
                     'Оплата за отпуск ' . $personVacationDay. ' дня' => $personVacationPay,
@@ -3009,6 +3082,14 @@ class CabinetService
                 'Командный бонус' => $teamBonusValue,
             );
 
+            if (!empty($personPremiumByStore)) {
+                $personBonusesArrayInfo = [
+                    'Премия за продажу фокусных позиции в праздники' => $personPremiumByStore,
+                ];
+                $variableSumValuesAdministrator = array_merge($personBonusesArrayInfo, $variableSumValuesAdministrator);
+            }
+
+
 
             $allVariableSumValuesAdministrator = array_sum($variableSumValuesAdministrator);
 
@@ -3057,6 +3138,14 @@ class CabinetService
                 'Премия за сборку матрицы' => $bonusMakeMatrix, //
                 'Премия за продажи не фокусной продукции (Другме товары)' => $userSalaryOtherItemsPremium,
             ];
+
+            if (!empty($personPremiumByStore)) {
+                $personBonusesArrayInfo = [
+                    'Премия за продажу фокусных позиции в праздники' => $personPremiumByStore,
+                ];
+                $bonusVariable = array_merge($personBonusesArrayInfo, $bonusVariable);
+            }
+
             $bonusVariableByMonth = [
                 'Премия за качество' => $userQualityPremium,
             ];
@@ -3070,6 +3159,14 @@ class CabinetService
                 $bonusVariableByMonth = array_merge($personBonusesArrayInfo, $bonusVariableByMonth);
             }
 
+
+            if (!empty($personPartTimeJobHoursPay)) {
+                $personBonusesArrayInfo = [
+                    'Оплата подработок по часам' . ' ('. $personPartTimeJobHours . '*' . $hourPayment . ' руб/час из оклада)'=> $personPartTimeJobHoursPay,
+                ];
+                $bonusVariableByMonth = array_merge($personBonusesArrayInfo, $bonusVariableByMonth);
+            }
+
             $bonusConstant = [
 
             ];
@@ -3112,6 +3209,20 @@ class CabinetService
                 $sumValuesFlorist = array_merge($personBonusesArrayInfo, $sumValuesFlorist);
             }
 
+            if (!empty($personPremiumByStore)) {
+                $personBonusesArrayInfo = [
+                    'Премия за продажу фокусных позиции в праздники' => $personPremiumByStore,
+                ];
+                $sumValuesFlorist = array_merge($personBonusesArrayInfo, $sumValuesFlorist);
+            }
+
+            if (!empty($personPartTimeJobHoursPay)) {
+                $personBonusesArrayInfo = [
+                    'Оплата подработок по часам' . ' ('. $personPartTimeJobHours . '*' . $hourPayment . ' руб/час из оклада)' => (int) $personPartTimeJobHoursPay,
+                ];
+                $arrayColumnWages = array_merge($arrayColumnWages, $personBonusesArrayInfo);
+            }
+
             if (!empty($personVacationPay)) {
                 $personBonusesArrayInfo = [
                     'Оплата за отпуск ' . $personVacationDay. ' дня' => $personVacationPay,
@@ -3171,6 +3282,14 @@ class CabinetService
                 'Премия за продажи не фокусной продукции (Другме товары)' => $userSalaryOtherItemsPremium,
             ];
 
+            if (!empty($personPremiumByStore)) {
+                $personBonusesArrayInfo = [
+                    'Премия за продажу фокусных позиции в праздники' => $personPremiumByStore,
+                ];
+                $bonusVariable = array_merge($personBonusesArrayInfo, $bonusVariable);
+            }
+
+
             $bonusVariableByMonth = [
                 'Премия за качество' => $userQualityPremium,
             ];
@@ -3183,6 +3302,15 @@ class CabinetService
                 ];
                 $bonusVariableByMonth = array_merge($personBonusesArrayInfo, $bonusVariableByMonth);
             }
+
+
+            if (!empty($personPartTimeJobHoursPay)) {
+                $personBonusesArrayInfo = [
+                    'Оплата подработок по часам' . ' ('. $personPartTimeJobHours . '*' . $hourPayment . ' руб/час из оклада)' => $personPartTimeJobHoursPay,
+                ];
+                $bonusVariableByMonth = array_merge($personBonusesArrayInfo, $bonusVariableByMonth);
+            }
+
             if (!empty($sumValuesFloristAnotherStore)) {
                 $bonusConstant = array_merge($bonusConstant, $sumValuesFloristAnotherStore);
             }
@@ -3208,9 +3336,20 @@ class CabinetService
 
         $alreadyPay = [
             'Аванс' => $personPrepaidExpense,
-            'Подсчет' => $personCounting,
         ];
 
+        if (!empty($personCounting)) {
+            $alreadyPay = array_merge($alreadyPay, [
+                'Подсчет' => $personCounting,
+            ]);
+        }
+
+        if (!empty($partTimeWagesSumAdminAllStore)) {
+            $alreadyPay = array_merge($alreadyPay, [
+                'Оплата подработок (количество смен ' . $partTimeWagesCountAdminAllStore . ')' => $partTimeWagesSumAdminAllStore,
+            ]);
+        }
+
         $personRetentionValue = 0;
 
         if (!empty($personRetention)) {
@@ -3218,13 +3357,21 @@ class CabinetService
         }
 
         $personRetentionArray = [
-            'Персональный вычет' => $personRetentionValue,
+            $personRetentionСomment => $personRetentionValue,
         ];
 
+        $sumPersonRetention = array_sum($personRetentionArray);
+
+        $alreadyPaySum = array_sum($alreadyPay);
+
         $minusSum = array_merge($alreadyPay, $personRetentionArray);
         $minusSumValue  = array_sum($minusSum);
         $toPayoff = $allTotalPayroll - $minusSumValue;
+
+        $allowShowPersonRetention = date('Y-m-d',time()) >= date('Y-m-t',strtotime($dateFrom));
+
         return [
+            'allowShowPersonRetention' => $allowShowPersonRetention,
             'dateFrom' => $dateFrom,
 
             'employeeId' => $employeeId,
@@ -3294,6 +3441,8 @@ class CabinetService
             'userQualityPremium' => $userQualityPremium ?? 0,
 
             'teamBonus' => $teamBonus ?? [], // 'Командный бонус'
+            'teamBonusDetail' => $teamBonusDetail ?? '', // 'Командный бонус детально'
+            'adminTeamPayrollTable' => $adminTeamPayrollTable ?? [], // 'Командный бонус детально'
             'teamBonusValue' => $teamBonusValue ?? 0, // 'Командный бонус'
 
             'userSalaryServicesPremium' => $userSalaryServicesPremium ?? [],
@@ -3303,6 +3452,8 @@ class CabinetService
 
             'arrUsersSalaryCheck' => $arrUsersSalaryCheck ?? [],
 
+            'showHolidayVersion' => $showHolidayVersion,
+
             'daysInSelectMonth' => $daysInSelectMonth,
             'daysRemainsInSelectMonth' => $daysRemainsInSelectMonth,
 
@@ -3368,9 +3519,17 @@ class CabinetService
 
             'personBonuses' => $personBonuses, // Персональная премия
             'personRetention' => $personRetention, // Персональный вычет
+            'personRetentionArray' => $personRetentionArray, // Персональный вычет массив
+            'sumPersonRetention' => $sumPersonRetention, // Персональный вычет сумма
+
             'personPrepaidExpense' => $personPrepaidExpense, // Аванс
             'personCounting' => $personCounting, // Подсчёт
 
+            'alreadyPay' => $alreadyPay, // Выплат за выбранный месяц
+            'alreadyPaySum' => $alreadyPaySum, // Сумма выплат за выбранный месяц
+            'partTimeWagesSumAdminAllStore' => $partTimeWagesSumAdminAllStore, // Оклады за подработку
+            'partTimeWagesCountAdminAllStore' => $partTimeWagesCountAdminAllStore, // Число смен подработок
+
             'toPayoff' => $toPayoff, // К выплате
 
             'oklad' => $oklad, // Оклад штатный
@@ -3444,6 +3603,18 @@ class CabinetService
             'sumChecksStore' => $sumChecksStore ?? 0,
             'sumIncomingTrafficStore' => $sumIncomingTrafficStore ?? 0,
             'conversionPercent' => $conversionPercent ?? 0,
+
+            'consolidatedArrUsersSalaryCheck' => $consolidatedArrUsersSalaryCheck ?? [],
+            'consolidatedPremiumByFocusGroups' => $consolidatedPremiumByFocusGroups ?? [],
+
+            'consolidatedPremiumByMatrix' => $consolidatedPremiumByMatrix ?? [],
+            'consolidatedPremiumByStore' => $consolidatedPremiumByStore ?? 0,
+
+            'onePartHolidayPremium' => $onePartHolidayPremium,
+            'adminsHolidayShiftCount' => $adminsHolidayShiftCount,
+            'personPremiumByStore' => $personPremiumByStore,
+            'personHolidayShiftCount' => $personHolidayShiftCount,
+
             'saveValuesOk' => 'ok',
         ];
     }
@@ -4307,10 +4478,6 @@ Group BY `admin_id`
      */
     public function getTimetableDate($timetable ,$employeeId , $adminGuid, array $storeAdminsGuids, $dateFrom, $dateTo, $normalCostShift, bool $isAdministrator, $entityCityStoreEmployeeSelect = null): array
     {
-
-
-
-
         $salesForAdmin = $this->getSalurySum($adminGuid, $dateFrom, $dateTo, $isAdministrator);
 
         $salesForStore = [];
@@ -4375,8 +4542,6 @@ Group BY `admin_id`
 
 
 
-
-
             $salesAdmins[$adminId] = [
                 'id' => $adminId,
                 'group_id' => $adminGroupIdRow,
@@ -4392,7 +4557,9 @@ Group BY `admin_id`
         $adminGroupId = AdminGroupDynamic::getGroupByDate($employeeId, $dateFrom, $dateTo);
 
         $timetableTemp = $timetable;
-
+        $partTimeWagesSum = 0;
+        $partTimeWagesCount = 0;
+        $parTimeWagesAdminIds = [];
         foreach ($timetableTemp as $keyTimetable => $row) {
 
 
@@ -4410,6 +4577,8 @@ Group BY `admin_id`
 
 
             $daySale = 0;
+            $timetable[$keyTimetable]['wagesInfo'] = '';
+            $wagesInfo = '';
 
             $timetable[$keyTimetable]['daySale'] = 0;
 
@@ -4430,11 +4599,21 @@ Group BY `admin_id`
             if ($isAdministrator && $timetable[$keyTimetable]['admin_id'] != $employeeId) {
                 $timetable[$keyTimetable]['wages'] = 0;
             } else {
-                $timetable[$keyTimetable]['wages'] = $normalCostShift;
+                $normalCostShiftRow = $normalCostShift;
+                if (!empty($row['salary_shift'])) {
+                    $normalCostShiftRow = ($row['salary_shift']);
+                }
+                $timetable[$keyTimetable]['wages'] = $normalCostShiftRow;
+                if ($row['d_id'] == Admin::PART_TIME_WORKER_GROUP_ID) {
+                    $timetable[$keyTimetable]['wagesInfo'] = 'подработка';
+                    $wagesInfo = ' (подработка)';
+                    $timetable[$keyTimetable]['partTimeWorkWages'] = $normalCostShiftRow;
+                    $partTimeWagesSum = $partTimeWagesSum + $normalCostShiftRow;
+                    $parTimeWagesAdminIds[] = $row['admin_id'];
+                    ++$partTimeWagesCount;
+                }
             }
 
-
-
             $timetableAdminsIds = ArrayHelper::getValue($row, 'timetable_admins_ids');
 
             $rateTimetableAdminsNames = [];
@@ -4471,8 +4650,6 @@ Group BY `admin_id`
                 ];
 
                 $adminsSales[$timetableAdminsId] = $sumRow;
-
-
             }
 
             $adminsSalesSum = 0;
@@ -4512,19 +4689,21 @@ Group BY `admin_id`
                 }
             }
 
-
-
             $adminNameColumn = ArrayHelper::getColumn($rateTimetableAdminsNames, 'name');
             $adminNameList = implode(',<br>' , $adminNameColumn);
 
-            $timetable[$keyTimetable]['typeSmena'] = $typeSmena;
+            $timetable[$keyTimetable]['typeSmena'] = $typeSmena . $wagesInfo;
             $timetable[$keyTimetable]['adminNameList'] = $adminNameList;
             $timetable[$keyTimetable]['typeSmenaInt'] = $typeSmenaInt;
             $timetable[$keyTimetable]['adminsSalesSum'] = $adminsSalesSum;
 
         }
 
-        return $timetable;
+        return [
+            'timetable' => $timetable,
+            'partTimeWagesSum' => $partTimeWagesSum,
+            'partTimeWagesCount' => $partTimeWagesCount,
+        ];
     }
 
 
@@ -6091,7 +6270,7 @@ Group BY `admin_id`
 
         $storeIdsString = ArrayHelper::getValue($clusterAdmin, 'store_arr');
         $clusterAdminId = ArrayHelper::getValue($clusterAdmin, 'id');
-        $storeIds = explode(',', $storeIdsString);
+        $storeIds = array_unique(explode(',', $storeIdsString));
 
         $groupIds = [
             Admin::ADMINISTRATOR_GROUP_ID // Администраторы
@@ -7484,4 +7663,241 @@ Group BY `admin_id`
         return $result;
     }
 
+    /**
+    * @return int
+    */
+    public function getAdministratorSalaryShift($employeeId, $dateFrom, $salesByStore = null) : int
+    {
+        $administratorOklad = 0;
+
+        if ($dateFrom >= '2023-12-01') {
+            $monthlySalary = EmployeePayment::getMonthlySalary($employeeId, $dateFrom);
+            $administratorOklad = ArrayHelper::getValue($monthlySalary, 'monthly_salary');
+
+        } else {
+            $administratorOklad = $this->bonusService->getAdministratorOklad($salesByStore);
+        }
+
+        return (int) $administratorOklad;
+    }
+
+    public function getPremiumByFocusGroups($adminGuid, $arrUsersSalary, $dateFrom, $dateTo, $isAdministrator): array
+    {
+        $userSalaryServices = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["services"])) {
+            $userSalaryServices = ($arrUsersSalary["services"][$adminGuid] > 0) ? $arrUsersSalary["services"][$adminGuid] : 0;
+        }// услуги
+
+        $userSalaryRelated = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["related"])) {
+            $userSalaryRelated = ($arrUsersSalary["related"][$adminGuid] > 0) ? $arrUsersSalary["related"][$adminGuid] : 0; // сопутка
+        }
+
+        $userSalaryPotted = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["potted"])) {
+            $userSalaryPotted = ($arrUsersSalary["potted"][$adminGuid] > 0) ? $arrUsersSalary["potted"][$adminGuid] : 0; // горшечка
+        }
+
+        $userSalaryWrap = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["wrap"])) {
+            $userSalaryWrap = ($arrUsersSalary["wrap"][$adminGuid] > 0) ? $arrUsersSalary["wrap"][$adminGuid] : 0; // упаковка
+        }
+
+        $userSalarySalut = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["salut"])) {
+            $userSalarySalut = ($arrUsersSalary["salut"][$adminGuid] > 0) ? $arrUsersSalary["salut"][$adminGuid] : 0; // пиротехника
+        }
+
+        $userSalaryOtherItems = 0;
+        if (array_key_exists($adminGuid, $arrUsersSalary["other_items"])) {
+            $userSalaryOtherItems = ($arrUsersSalary["other_items"][$adminGuid] > 0) ? $arrUsersSalary["other_items"][$adminGuid] : 0; // Другие товары
+        }
+
+        $userSalaryServicesPremium = round($userSalaryServices * 0.1); // 10% за продажу услуг
+        $userSalaryRelatedPremium = round($userSalaryRelated * 0.05); // 5% за личные продажи сопутки
+        $userSalaryPottedPremium = round($userSalaryPotted * 0.05);
+        $userSalaryWrapPremium = round($userSalaryWrap * 0.05); // 5% за личные продажи упаковки
+
+        $userSalarySalutPremium  = round($userSalarySalut * 0.05); // 5% за личные продажи пиротехники
+
+        $userSalaryOtherItemsPremium  = round($userSalaryOtherItems * 0.01); // 1% за личные продажи не фокусной продукции (Другме товары)
+
+        $userSalaryPremium = [
+            'userSalaryServicesPremium' => $userSalaryServicesPremium,
+            'userSalaryRelatedPremium' => $userSalaryRelatedPremium,
+            'userSalaryPottedPremium' => $userSalaryPottedPremium,
+            'userSalaryWrapPremium' => $userSalaryWrapPremium,
+            'userSalarySalutPremium' => $userSalarySalutPremium,
+            'userSalaryOtherItemsPremium' => $userSalaryOtherItemsPremium,
+        ];
+
+        $userSalaryPremiumSum = array_sum($userSalaryPremium);
+
+        return [
+            'userSalaryServices' => $userSalaryServices,
+            'userSalaryServicesPremium' => $userSalaryServicesPremium,
+            'userSalaryRelated' => $userSalaryRelated,
+            'userSalaryRelatedPremium' => $userSalaryRelatedPremium,
+            'userSalaryPotted' => $userSalaryPotted,
+            'userSalaryPottedPremium' => $userSalaryPottedPremium,
+            'userSalaryWrap' => $userSalaryWrap,
+            'userSalaryWrapPremium' => $userSalaryWrapPremium,
+            'userSalarySalut' => $userSalarySalut,
+            'userSalarySalutPremium' => $userSalarySalutPremium,
+            'userSalaryOtherItems' => $userSalaryOtherItems,
+            'userSalaryOtherItemsPremium' => $userSalaryOtherItemsPremium,
+            'userSalaryPremiumSum' => $userSalaryPremiumSum,
+        ];
+    }
+
+    public function getPremiumByMatrix(
+        $employeeSelectStoreId,
+        $adminGuid,
+        $dateFrom,
+        $dateTo,
+        $isAdministrator,
+        $showHolidayVersion = false,
+        $notHolidayCalculate = true
+    ): array {
+        $adminGuidDateArr = [];
+        $adminGuidArrAll = [];
+        if ($showHolidayVersion) {
+            $holidayDatesBetweenPrepared = HolidayService::getHolidayDatesBetween($dateFrom, $dateTo);
+            if ($notHolidayCalculate) {
+                $dataKey = 'notHolidayDatesInterval';
+            } else {
+                $dataKey = 'dayHolidayInArray';
+                $adminGuidDateArr = SalaryHelper::getAdminGuidByStore($dateFrom, $dateTo, $employeeSelectStoreId);
+                $isAdministrator = false;
+            }
+            $dates = ArrayHelper::getValue($holidayDatesBetweenPrepared,  $dataKey);
+        } else {
+            $dates = [
+                0 => [
+                    'dateFrom' => $dateFrom,
+                    'dateTo' => $dateTo,
+                ],
+            ];
+        }
+
+        $salesMatrixTemp = [];
+        $makeMatrixTemp = [];
+
+        foreach ($dates as $key => $datesRow) {
+            $dateFromRow = $datesRow['dateFrom'];
+            $dateToRow = $datesRow['dateTo'];
+            $adminGuids = [];
+            if (
+                true === $showHolidayVersion
+                &&
+                $dateFromRow == $dateToRow
+                &&
+                !empty($adminGuidDateArr)
+
+            ) {
+                if (array_key_exists($dateFromRow, $adminGuidDateArr)) {
+                    $adminGuids = $adminGuidDateArr[$dateFromRow];
+                    $adminGuidArrAll[] = $adminGuids;
+                } else {
+                    $testtt = 0;
+                    continue;
+                }
+            }
+
+            //Букеты по матрице
+
+            $salesMatrixRow = $this->salesService->getMatrixSalesProducts($adminGuid, $dateFromRow, $dateToRow, $isAdministrator, $adminGuids);
+            $salesMatrixTemp = array_merge($salesMatrixTemp, $salesMatrixRow);
+
+
+            $makeMatrixRow = $this->salesService->getMatrixMakeProducts($adminGuid, $dateFromRow, $dateToRow, $isAdministrator, $adminGuids);
+            $makeMatrixTemp = array_merge($makeMatrixTemp, $makeMatrixRow);
+        }
+
+        $productMatrixTemp = array_merge($salesMatrixTemp, $makeMatrixTemp);
+
+        $adminGuidNames = Admin::getAdminGuidNames();
+
+        $matrixProductGuids = ArrayHelper::getColumn($productMatrixTemp, 'product_guid');
+        $matrixProducts = Products1c::getProducts1cByType('products', $matrixProductGuids);
+        $matrixProductNames = ArrayHelper::map($matrixProducts, 'id', 'name');
+
+        $salaryMatrix = 0;
+        $bonusSalaryMatrix = 0;
+        $salesMatrix = $salesMatrixTemp;
+        foreach ($salesMatrixTemp as $keySalesMatrix => $row) {
+            $matrixBonusCoefficientRow = $this->bonusService->getMatrixBonusCoefficient($row['date']);
+            $rowBonus = $row["summ"] * $matrixBonusCoefficientRow;
+            $salesMatrix[$keySalesMatrix]["bonus"] = $rowBonus;
+            if ($row["operation"] == Sales::OPERATION_SALE) {
+                $salaryMatrix += $row["summ"];
+                $bonusSalaryMatrix += $rowBonus;
+            } elseif ($row["operation"] == Sales::OPERATION_RETURN) {
+                $salaryMatrix -= $row["summ"];
+                $bonusSalaryMatrix -= $rowBonus;
+            }
+            $productNameRow = '';
+            if (array_key_exists($row["product_guid"], $matrixProductNames)) {
+                $productNameRow = ArrayHelper::getValue($matrixProductNames, $row["product_guid"]);
+            }
+            $salesMatrix[$keySalesMatrix]["product_name"] = $productNameRow;
+
+            if (!$notHolidayCalculate) {
+                $adminNameRow = '';
+                if (array_key_exists($row["seller_id"], $adminGuidNames)) {
+                    $adminNameRow = ArrayHelper::getValue($adminGuidNames, $row["seller_id"]);
+                }
+                $salesMatrix[$keySalesMatrix]["admin_name"] = $adminNameRow;
+            }
+        }
+
+        $bonusSalaryMatrix = round($bonusSalaryMatrix);
+
+
+        $salaryMakeMatrix = 0;
+        $bonusMakeMatrix = 0;
+        $makeMatrix = $makeMatrixTemp;
+        foreach ($makeMatrixTemp as $kayMakeMatrix => $row) {
+            $matrixBonusCoefficientRow = $this->bonusService->getMatrixBonusCoefficient($row['date']);
+            $rowBonus = $row["summ"] * $matrixBonusCoefficientRow;
+            $makeMatrix[$kayMakeMatrix]["bonus"] = $rowBonus;
+            if ($row["operation"] == Sales::OPERATION_SALE) {
+                $salaryMakeMatrix += $row["summ"];
+                $bonusMakeMatrix += $rowBonus;
+            } elseif ($row["operation"] == Sales::OPERATION_RETURN) {
+                $salaryMakeMatrix -= $row["summ"];
+                $bonusMakeMatrix -= $rowBonus;
+            }
+
+            $productNameRow = '';
+            if (array_key_exists($row["product_guid"], $matrixProductNames)) {
+                $productNameRow = ArrayHelper::getValue($matrixProductNames, $row["product_guid"]);
+            }
+            $makeMatrix[$kayMakeMatrix]["product_name"] = $productNameRow;
+
+            if (!$notHolidayCalculate) {
+                $adminNameRow = '';
+                if (array_key_exists($row["seller_id"], $adminGuidNames)) {
+                    $adminNameRow = ArrayHelper::getValue($adminGuidNames, $row["seller_id"]);
+                }
+                $makeMatrix[$kayMakeMatrix]["admin_name"] = $adminNameRow;
+            }
+        }
+
+        $bonusMakeMatrix = round($bonusMakeMatrix);
+
+        // итого: премия с матрицы
+        $matrixPrime = $bonusSalaryMatrix + $bonusMakeMatrix;
+
+        return [
+            'salesMatrix' => $salesMatrix,
+            'bonusSalaryMatrix' => $bonusSalaryMatrix,
+            'makeMatrix' => $makeMatrix,
+            'salaryMatrix' => $salaryMatrix,
+            'salaryMakeMatrix' => $salaryMakeMatrix,
+            'bonusMakeMatrix' => $bonusMakeMatrix,
+            'matrixPrime' => $matrixPrime,
+            'adminGuidDateArrByMatrix' => $adminGuidArrAll,
+        ];
+    }
 }
index 685d2e3fb1d5bf172dfeed346e8a74105c2ceb49..a64816a05d969b9d6e4c726eba466e16a01fc8c3 100755 (executable)
@@ -452,6 +452,7 @@ class DashboardService
             $data = $command->queryAll();
 
             $dataArraySalesAll = [];
+            $dataSaleCumulative = [];
             $SalesMStores = [];
             $SalesM = [];
 
@@ -558,7 +559,17 @@ class DashboardService
                 } else {
                     continue;
                 }
-                $sale = $dataSaleCumulative[$row["date_p"]][$storeId];
+                $sale = 0;
+
+                if (
+                    array_key_exists($row["date_p"], $dataSaleCumulative)
+                    &&
+                    array_key_exists($storeId, $dataSaleCumulative[$row["date_p"]])
+                    &&
+                    !empty($dataSaleCumulative[$row["date_p"]][$storeId])
+                ) {
+                    $sale = $dataSaleCumulative[$row["date_p"]][$storeId];
+                }
 
 
                 if (!array_key_exists($row["date_m"], $write_offs)) {
diff --git a/erp24/services/HolidayService.php b/erp24/services/HolidayService.php
new file mode 100644 (file)
index 0000000..3c60ded
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+
+
+namespace yii_app\services;
+
+
+use yii_app\helpers\DateHelper;
+
+class HolidayService
+{
+    private static array $holiday = [
+        '2024-03-05',
+        '2024-03-06',
+        '2024-03-07',
+        '2024-03-08',
+    ];
+
+    public static function getHoliday(): array
+    {
+        return self::$holiday;
+    }
+
+
+    public static function getHolidayVersionShow($dateFrom, $dateTo): bool
+    {
+        $datesBetween = DateHelper::getDatesBetween($dateFrom, $dateTo);
+
+        $holidays = self::getHoliday();
+
+        $dayHolidayIn = (array_uintersect($holidays, $datesBetween, "strcasecmp"));
+
+        $dayHolidayVersion = false;
+
+        if (!empty($dayHolidayIn)) {
+            $dayHolidayVersion = true;
+        }
+
+        return $dayHolidayVersion;
+    }
+
+
+    public static function getHolidayDatesBetween($dateFrom, $dateTo): array
+    {
+        $datesBetween = DateHelper::getDatesBetween($dateFrom, $dateTo);
+
+        $holidays = self::getHoliday();
+
+        $dayHolidayIn = (array_uintersect($holidays, $datesBetween, "strcasecmp"));
+
+        $keyInterval = 1;
+        $datesIntervals = [];
+        foreach ($datesBetween as $item) {
+            if (!in_array($item, $holidays)) {
+                $datesIntervals[$keyInterval][] = $item;
+            } else {
+                ++$keyInterval;
+            }
+        }
+
+        $notHolidayDatesInterval = [];
+        if (!empty($datesIntervals)) {
+            foreach ($datesIntervals as $row) {
+                $notHolidayDatesInterval[] = [
+                    'dateFrom' => $row[array_key_first($row)],
+                    'dateTo' => $row[array_key_last($row)],
+                ];
+            }
+        }
+        $holidaysDatesInterval = [];
+
+        if (!empty($dayHolidayIn)) {
+            foreach ($dayHolidayIn as $row) {
+                $holidaysDatesInterval[] = [
+                    'dateFrom' => $row,
+                    'dateTo' => $row,
+                ];
+            }
+        }
+
+        return [
+            'dayHolidayInArray' => $holidaysDatesInterval,
+            'notHolidayDatesInterval' => $notHolidayDatesInterval,
+        ];
+    }
+}
\ No newline at end of file
index 40350b184d2129cb16b54321a5ba0dea7377334b..33c39f1f997b4ff4371bc8b7b140d97f721dbfbc 100755 (executable)
@@ -1076,7 +1076,6 @@ class SalesService
     }
 
 
-
     /**
      * "СТАРУЮ МАТРИЦУ" пробитую до 16.11 в зп начисляем как 2,5 %,
      * с 16.11 по 7.12 за "СТАРУЮ МАТРИЦУ" НАЧИСЛЯЕМ 2%, после 7.12 ее не считаем в ЗП совсем.
@@ -1085,18 +1084,24 @@ class SalesService
      * @param string $adminGuid
      * @param string $dateFrom
      * @param string $dateTo
+     * @param $isAdministrator
+     * @param null $adminGuids
      * @return array
      * @throws \yii\db\Exception
      */
-    public function getMatrixSalesProducts(string $adminGuid, string $dateFrom, string $dateTo, $isAdministrator) : array
+    public function getMatrixSalesProducts(string $adminGuid, string $dateFrom, string $dateTo, $isAdministrator, $adminGuids = null) : array
     {
         $adminsGuids = $this->adminsGuids;
 
         $adminId = null;
-        if (array_key_exists($adminGuid, $adminsGuids)) {
+        if (array_key_exists($adminGuid, $adminsGuids) && empty($adminGuids)) {
             $adminId = ArrayHelper::getValue($adminsGuids, $adminGuid);
         }
 
+        if (!empty($adminGuids) && is_array($adminGuids)) {
+            $adminGuid = implode("','", $adminGuids);
+        }
+
         $dateTimeStartDay = false;
         $dateTimeEndDay = false;
 
@@ -1125,7 +1130,7 @@ class SalesService
                     sales_products as p,
                     sales 
                 WHERE 
-                    sales.seller_id = :admin_guid 
+                    sales.seller_id IN ('$adminGuid')
                 AND 
                     sales.id = p.check_id
                 AND (
@@ -1155,7 +1160,7 @@ class SalesService
                     sales.date ASC 
             
             ",
-                [   ':admin_guid' => $adminGuid,
+                [
                     ':date_from' => DateHelper::getDateTimeStartDay($dateFrom, $dateTimeStartDay, $adminId),
                     ':date_to' => DateHelper::getDateTimeEndDay($dateTo, $dateTimeEndDay, $adminId),
                 ]
@@ -1244,6 +1249,8 @@ class SalesService
             );
         }
 
+        $action = $command->getRawSql();
+
         return $command->queryAll();
     }
 
@@ -1352,18 +1359,24 @@ class SalesService
      * @param string $adminGuid
      * @param string $dateFrom
      * @param string $dateTo
+     * @param bool $isAdministrator
+     * @param null|array $adminGuids
      * @return array
      * @throws \yii\db\Exception
      */
-    public function getMatrixMakeProducts(string $adminGuid, string $dateFrom, string $dateTo, $isAdministrator) : array
+    public function getMatrixMakeProducts(string $adminGuid, string $dateFrom, string $dateTo,bool $isAdministrator, $adminGuids = null) : array
     {
         $adminsGuids = $this->adminsGuids;
 
         $adminId = null;
-        if (array_key_exists($adminGuid, $adminsGuids)) {
+        if (array_key_exists($adminGuid, $adminsGuids) && empty($adminGuids)) {
             $adminId = ArrayHelper::getValue($adminsGuids, $adminGuid);
         }
 
+        if (!empty($adminGuids) && is_array($adminGuids)) {
+            $adminGuid = implode("','", $adminGuids);
+        }
+
         $dateTimeStartDay = false;
         $dateTimeEndDay = false;
 
@@ -1378,7 +1391,7 @@ class SalesService
             $command = $connection->createCommand("
                 SELECT
                     DISTINCT (sales.id),
-                    sales.seller_id,
+                    p.seller_id,
                     sales.date,
                     sales.number,
                     (p.summ) AS summ,
@@ -1392,7 +1405,7 @@ class SalesService
                     sales_products as p,
                     sales 
                 WHERE 
-                    p.seller_id = :admin_guid 
+                    p.seller_id IN ('$adminGuid')
                 AND 
                     sales.id = p.check_id
                 AND (
@@ -1422,7 +1435,7 @@ class SalesService
                     sales.date ASC 
             
             ",
-                [':admin_guid' => $adminGuid,
+                [
                     ':date_from' => DateHelper::getDateTimeStartDay($dateFrom, $dateTimeStartDay, $adminId),
                     ':date_to' => DateHelper::getDateTimeEndDay($dateTo, $dateTimeEndDay, $adminId),
                 ]
@@ -1443,7 +1456,7 @@ class SalesService
                     sales_products as p,
                     sales 
                 WHERE 
-                    p.seller_id = :admin_guid 
+                    p.seller_id IN ('$adminGuid') 
                 AND 
                     sales.id = p.check_id
                 AND (
@@ -1474,7 +1487,7 @@ class SalesService
                     sales_products as p,
                     sales 
                 WHERE 
-                    p.seller_id = :admin_guid 
+                    p.seller_id IN ('$adminGuid')  
                 AND 
                     sales.id = p.check_id
                 AND (
@@ -1502,13 +1515,17 @@ class SalesService
                     sales.date <= :date_to
             
             ",
-                [':admin_guid' => $adminGuid,
+                [
                     ':date_from' => DateHelper::getDateTimeStartDay($dateFrom, $dateTimeStartDay, $adminId),
                     ':date_to' => DateHelper::getDateTimeEndDay($dateTo, $dateTimeEndDay, $adminId),
                 ]
             );
         }
 
+
+        $action = $command->getRawSql();
+
+
         return $command->queryAll();
     }
 
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/erp24/tests/_data/.gitignore b/erp24/tests/_data/.gitignore
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/erp24/tests/_data/city.php b/erp24/tests/_data/city.php
new file mode 100755 (executable)
index 0000000..966a63d
--- /dev/null
@@ -0,0 +1,15 @@
+<?php
+
+return [
+    [
+        'name' => 'Город тест',
+        'code' => 'city-test',
+        'social' => 'socialsocial',
+        'phone' => '+7 (232) 4-335-647',
+           'email' => 'nicole.paucek@schultz.info',
+           'phone_support' => '8 800 770 70 22',
+        'active' => '1',
+        'created_at' => '1402312317',
+        'updated_at' => '1402312317',
+    ],
+];
old mode 100644 (file)
new mode 100755 (executable)
index c96a04f..d6b7ef3
@@ -1,2 +1,2 @@
 *
-!.gitignore
\ No newline at end of file
+!.gitignore
diff --git a/erp24/tests/_support/.gitignore b/erp24/tests/_support/.gitignore
new file mode 100755 (executable)
index 0000000..36e264c
--- /dev/null
@@ -0,0 +1 @@
+_generated
old mode 100644 (file)
new mode 100755 (executable)
index db2ce28..43327cb
@@ -1,5 +1,8 @@
 <?php
+namespace backend\tests;
 
+use Codeception\Actor;
+use Codeception\Lib\Friend;
 
 /**
  * Inherited Methods
  * @method void am($role)
  * @method void lookForwardTo($achieveValue)
  * @method void comment($description)
- * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
+ * @method Friend haveFriend($name, $actorClass = NULL)
  *
  * @SuppressWarnings(PHPMD)
-*/
-class FunctionalTester extends \Codeception\Actor
+ */
+class FunctionalTester extends Actor
 {
     use _generated\FunctionalTesterActions;
-
+   /**
+    * Define custom actions here
+    */
 }
old mode 100644 (file)
new mode 100755 (executable)
index 2835357..36e1eba
@@ -1,5 +1,8 @@
 <?php
+namespace backend\tests;
 
+use Codeception\Actor;
+use Codeception\Lib\Friend;
 
 /**
  * Inherited Methods
  * @method void am($role)
  * @method void lookForwardTo($achieveValue)
  * @method void comment($description)
- * @method \Codeception\Lib\Friend haveFriend($name, $actorClass = NULL)
+ * @method Friend haveFriend($name, $actorClass = NULL)
  *
  * @SuppressWarnings(PHPMD)
-*/
-class UnitTester extends \Codeception\Actor
+ */
+class UnitTester extends Actor
 {
     use _generated\UnitTesterActions;
-
    /**
     * Define custom actions here
     */
diff --git a/erp24/tests/fixtures/CityFixture.php b/erp24/tests/fixtures/CityFixture.php
new file mode 100755 (executable)
index 0000000..44d0e70
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+namespace backend\tests\fixtures;
+
+use yii\test\ActiveFixture;
+
+class CityFixture extends ActiveFixture
+{
+    public $modelClass = 'backend\models\City';
+}
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
diff --git a/erp24/tests/functional/CityCest.php b/erp24/tests/functional/CityCest.php
new file mode 100755 (executable)
index 0000000..166acb3
--- /dev/null
@@ -0,0 +1,124 @@
+<?php namespace backend\tests\functional;
+use backend\models\City;
+use backend\tests\fixtures\CityFixture;
+use backend\tests\FunctionalTester;
+use Codeception\Example;
+use common\fixtures\UserFixture;
+
+class CityCest
+{
+    public function _before(FunctionalTester $I)
+    {
+    }
+
+       /**
+        * Load fixtures before db transaction begin
+        * Called in _before()
+        * @see \Codeception\Module\Yii2::_before()
+        * @see \Codeception\Module\Yii2::loadFixtures()
+        * @return array
+        */
+       public function _fixtures()
+       {
+               return [
+                       'user' => [
+                               'class' => UserFixture::className(),
+                               'dataFile' => codecept_data_dir() . 'login_data.php'
+                       ],
+                       'city' => [
+                               'class' => CityFixture::className(),
+                               'dataFile' => codecept_data_dir() . 'city.php'
+                       ]
+
+               ];
+       }
+
+       /**
+        * @param FunctionalTester $I
+        * @dataProvider pageProvider
+        */
+       public function testSortLinkClick(FunctionalTester $I, Example $data)
+       {
+               $pageH1 = 'Города';
+               $I->amLoggedInAs(1);
+
+               $I->amOnPage('/city/');
+               $I->see($pageH1, 'h1');
+               $I->click(['link' => $data['link']]);
+               $I->see($pageH1, 'h1');
+               $I->seeInTitle($pageH1);
+               $I->click(['link' => $data['link']]);
+               $I->see($pageH1, 'h1');
+               $I->seeInTitle($pageH1);
+
+       }
+
+       /**
+        * @return array
+        */
+       protected function pageProvider()
+       {
+               return [
+                       ['link'=>"Название"],
+                       ['link'=>"Символьный код"],
+                       ['link'=>"Телефон"],
+                       ['link'=>"Активность"],
+               ];
+       }
+
+
+
+       /**
+        * @param FunctionalTester $I
+        */
+       public function createCity(FunctionalTester $I)
+       {
+
+               $I->amLoggedInAs(1);
+
+               $I->amOnPage('/city/create/');
+               $I->fillField('City[name]', 'Город Город');
+               $I->fillField('City[code]', 'codecity');
+               $I->fillField('City[phone]', '+7 (132) 4-542-132');
+               $I->click('Сохранить');
+
+               $I->see('Город Город');
+
+       }
+
+       /**
+        * @param FunctionalTester $I
+        */
+       public function viewCity(FunctionalTester $I)
+       {
+               $I->amLoggedInAs(1);
+
+               $model = City::find()->one();
+
+               $urlView = '/city/view/'.$model->id.'/';
+               $name = $model->name;
+               $I->amOnPage($urlView);
+               $I->click(['link' => 'Изменить']);
+
+               $I->see($name);
+
+       }
+
+       /**
+        * @param FunctionalTester $I
+        */
+       public function updateCity(FunctionalTester $I)
+       {
+               $I->amLoggedInAs(1);
+
+               $model = City::find()->one();
+
+               $urlView = '/city/update/'.$model->id.'/';
+               $name = $model->name;
+               $I->amOnPage($urlView);
+               $I->click('Сохранить');
+
+               $I->see($name);
+
+       }
+}
old mode 100644 (file)
new mode 100755 (executable)
index b3d9bbc..30ed54b
@@ -1 +1,16 @@
 <?php
+/**
+ * Here you can initialize variables via \Codeception\Util\Fixtures class
+ * to store data in global array and use it in Cests.
+ *
+ * ```php
+ * // Here _bootstrap.php
+ * \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
+ * ```
+ *
+ * In Cests
+ *
+ * ```php
+ * \Codeception\Util\Fixtures::get('user1');
+ * ```
+ */
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index c14e49c..78c67c9
@@ -1,11 +1,13 @@
-# Codeception Test Suite Configuration
-
-# suite for unit (internal) tests.
-# RUN `build` COMMAND AFTER ADDING/REMOVING MODULES.
-
+suite_namespace: tests\unit
 actor: UnitTester
+bootstrap: false
 modules:
-    enabled:
-      - Asserts
-      - Yii2:
-            part: [orm, email, fixtures]
+  enabled:
+    - Yii2:
+        part: [orm, email, fixtures]
+    - Asserts
+coverage:
+  enabled: true
+  whitelist:
+    include:
+      - models/*
old mode 100644 (file)
new mode 100755 (executable)
index 80cc72a..e432ce5
@@ -1,3 +1,16 @@
 <?php
-
-// add unit testing specific bootstrap code here
+/**
+ * Here you can initialize variables via \Codeception\Util\Fixtures class
+ * to store data in global array and use it in Tests.
+ *
+ * ```php
+ * // Here _bootstrap.php
+ * \Codeception\Util\Fixtures::add('user1', ['name' => 'davert']);
+ * ```
+ *
+ * In Tests
+ *
+ * ```php
+ * \Codeception\Util\Fixtures::get('user1');
+ * ```
+ */
diff --git a/erp24/tests/unit/models/CityTest.php b/erp24/tests/unit/models/CityTest.php
new file mode 100755 (executable)
index 0000000..788ab43
--- /dev/null
@@ -0,0 +1,389 @@
+<?php
+
+namespace backend\tests\unit\models;
+
+use Codeception\Test\Unit;
+use common\tests\UnitTester;
+use Yii;
+use backend\models\City;
+use backend\tests\fixtures\CityFixture;
+
+/**
+ * Login form test
+ */
+class CityTest extends Unit
+{
+    /**
+     * @var UnitTester
+     */
+    protected $tester;
+       protected $className;
+
+       protected function _before()
+       {
+
+               $this->className = City::className();
+
+       }
+
+
+    /**
+     * @return array
+     */
+    public function _fixtures()
+    {
+        return [
+            'city' => [
+                'class' => CityFixture::className(),
+                'dataFile' => codecept_data_dir() . 'city.php'
+            ]
+        ];
+    }
+
+       public function testEmptyValues()
+       {
+               $model = new $this->className;
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+       }
+
+       public function testNameOnly()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'name' => 'Город'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+
+       }
+       public function testWrongName()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'name' => 'one title'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key name must have in array errors', $model->errors)->hasKey('name');
+
+       }
+
+       public function testShortName()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'name' => 'H'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key name must have in array errors', $model->errors)->hasKey('name');
+
+       }
+
+       public function testFieldActiveNotInteger()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'active' => 'string'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key active must have in array errors', $model->errors)->hasKey('active');
+
+       }
+
+       public function testLongPhoneSupport()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'phone_support' => '123456789012345678901'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key phone_support must have in array errors', $model->errors)->hasKey('phone_support');
+
+       }
+
+       /**
+        * @dataProvider providerIntegerFields
+        */
+       public function testIntegerFieldsWrongSetRussianText($a)
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       $a => 'Название'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key '.$a.' must have in array errors', $model->errors)->hasKey($a);
+
+       }
+
+       /**
+        * @return array
+        */
+       public function providerIntegerFields()
+       {
+               $obj = new City();
+               return $obj->getAllFieldsGroupByType()->getFieldsByType('integer');
+       }
+
+
+       public function testLongPhone()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'phone' => '123456789012345678901'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key phone must have in array errors', $model->errors)->hasKey('phone');
+
+       }
+
+       public function testLongName()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'name' => 'цщукзшгецзщушкгезщцушкгезщцшугкещзшугкцезщшгцзукешгцушгкеншщцугкенщшгншщгцункещшцгукеншщгцкежрлордорфжваопрфваопрылжвоапрыдлвоапрывалопрылдвоапрылваопрлыдпаловаарыплдоршдкгеншгукрпвшгкеершупоыаршгнкешыгарлыовврппршгыукрлпоыршгыукршшывгралопршыгкршорпчлоавр'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key name must have in array errors', $model->errors)->hasKey('name');
+
+       }
+
+       public function testLongCode()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'code' => 'qwertwpieurtypiweurtyiweurtyioweurytioweurytioweurtyioaslkjdfhklajfhlkjahfklgjahdkfjghkadjfgkajdfgkajddfhgkajddfhkgkjaddhfkgkjadhfkgkjahdkfjghklazcvbvbzkcvjhblzkcvjhblkzjcvhblkzuvycoiuzyoiuyzouvybozhvblzvzuvbhoizuvcybiozucvhbzjcvhobzciuvhkjewrhtklwjehrtklj'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key code must have in array errors', $model->errors)->hasKey('code');
+
+       }
+
+//[['name', 'code', 'phone', 'email'], 'string', 'min' => 2, 'max' => 255],
+       public function testShortPhoneSupport()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'phone_support' => '1'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key phone_support must have in array errors', $model->errors)->hasKey('phone_support');
+
+       }
+
+       public function testShortPhone()
+       {
+               $model = new $this->className;
+
+               $model->attributes = [
+                       'phone' => '1'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key phone must have in array errors', $model->errors)->hasKey('phone');
+
+       }
+
+       public function testNotUniqueName()
+       {
+               $model = new $this->className;
+
+               $nameCityTest = 'Город тест';
+
+               $model->attributes = [
+                       'name' => $nameCityTest,
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect($model->getFirstError('name'));
+               expect('key name must have in array errors', $model->errors)->hasKey('name');
+
+       }
+
+       public function testNotUniqueCode()
+       {
+               $model = new $this->className;
+
+               $codeTest = 'city-test';
+
+//             $message = 'Значение «'.$codeTest.'» для «Символьный код» уже занято.';
+
+               $model->attributes = [
+                       'code' => $codeTest,
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+               expect('key code must have in array errors', $model->errors)->hasKey('code');
+       }
+
+       public function testWrongCode()
+       {
+               $model = new $this->className;
+
+               $codeTest = 'фываы';
+
+//             $message = 'Значение «'.$codeTest.'» для «Символьный код» уже занято.';
+
+               $model->attributes = [
+                       'code' => $codeTest,
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+//             $test = $model->getFirstError('code');
+//             expect($model->getFirstError('code'))->equals($message);
+               expect('key code must have in array errors', $model->errors)->hasKey('code');
+
+       }
+
+    public function testCityWrongMail()
+    {
+               $model = new $this->className;
+               $model->attributes = [
+                       'email' => 'WrongMail'
+               ];
+
+               $validate = $model->validate();
+
+               expect('Validation should be failed', $validate)->false();
+               expect($model->hasErrors())->true();
+//             expect($model->getFirstError('email'))->equals('Значение «E-mail» не является правильным email адресом.');
+           expect('key email must have in array errors', $model->errors)->hasKey('email');
+       }
+
+    public function testTrueCity()
+    {
+               $model = new $this->className;
+           $expectedAttrs = [
+                   'name' => 'Город Тест Тест',
+                   'code' => 'testcode',
+                   'phone' => '+7 (332) 4-375-847',
+                   'email' => 'nicuole.pacek@schultz.info',
+                   'phone_support' => '8 800 770 70 22',
+                   'active' => '1',
+                   'created_at' => '1402312317',
+                   'updated_at' => '1402312317',
+           ];
+
+               $model->attributes = $expectedAttrs;
+
+               expect('Validation should be success', $model->validate())->true();
+               expect($model->hasErrors())->false();
+
+           $this->assertTrue($model->save());
+
+           $expectedAttrs['id'] = $model->id;
+
+           $city = City::find()->where(['id' =>$expectedAttrs['id']])->one();
+           $this->assertNotNull($city);
+
+           $this->assertEquals($expectedAttrs['name'], $city->name);
+           $this->tester->assertEquals($expectedAttrs['name'], $city->name);
+
+               $this->assertEquals($expectedAttrs['email'], $city->email);
+               $this->assertEquals($expectedAttrs['code'], $city->code);
+
+       }
+
+       public function testDeleteCity()
+       {
+               // delete
+               $record = new $this->className;
+               $record->name = 'Город Тест Тест Первый Тест';
+               $record->code = 'testcode';
+               $record->phone = '+7 (332) 4-375-847';
+               $record->email = 'nicuole.pacek@schultz.info';
+               $record->phone_support = '8 800 770 70 22';
+               $record->active = 1;
+               $record->created_at = 1402312317;
+               $record->updated_at = 1402312317;
+
+               $record->save();
+
+               $recordId = $record->id;
+
+               $record = City::findOne($recordId);
+               $record->delete();
+               $record = City::findOne($recordId);
+               $this->assertNull($record);
+
+               // deleteAll
+               $record = new $this->className;
+               $record->name = 'Город Тест Тест Второй Тест';
+               $record->code = 'testcode';
+               $record->phone = '+7 (332) 4-375-847';
+               $record->email = 'nicuole.pacek@schultz.info';
+               $record->phone_support = '8 800 770 70 22';
+               $record->active = 1;
+               $record->created_at = 1402312317;
+               $record->updated_at = 1402312317;
+               $record->save();
+
+               $ret = City::deleteAll(['name' => 'Город Тест Тест Второй Тест']);
+               $this->assertEquals(1, $ret);
+               $records = City::find()->where(['name' => 'Город Тест Тест Второй Тест'])->all();
+               $this->assertEquals(0, count($records));
+       }
+}
index b483be1df8b7b8b0f5979259ddc27851a1db1324..96205dbba3eff9e52e08e6d6008453c182aa7794 100755 (executable)
@@ -52,7 +52,7 @@ use yii_app\records\Admin;
         ]); ?>
 
     <?= $form->field($model, 'year')->dropDownList(
-        array_combine(range(2022,2026),range(2022,2026))
+        array_combine(range(2022,2028),range(2022,2028))
     )  ?>
 
     <?= $form->field($model, 'month')->dropDownList(
@@ -67,6 +67,10 @@ use yii_app\records\Admin;
 
     <?= $form->field($model, 'retention')->textInput() ?>
 
+    <?= $form->field($model, 'retention_comment')->textarea() ?>
+
+    <?= $form->field($model, 'part_time_job_hours')->textInput() ?>
+
     <?= $form->field($model, 'shift_correction')->textInput() ?>
 
     <?= $form->field($model, 'prepaid_expense')->textInput() ?>
index 53b94a25d648643c79ce74ce1a5ab2e011536d22..2ab320d4e455a1685a41d35ba681a1c8881e0513 100755 (executable)
@@ -30,6 +30,8 @@ use yii_app\records\Admin;
     <?= $form->field($model, 'vacation_day')->textInput() ?>
 
     <?= $form->field($model, 'retention')->textInput() ?>
+    <?= $form->field($model, 'retention_comment')->textarea() ?>
+    <?= $form->field($model, 'part_time_job_hours')->textInput() ?>
 
     <?= $form->field($model, 'shift_correction')->textInput() ?>
 
index d1437009e935ad0749007861d599fe215b6012da..215d20e6f8f211ba1bf061dcceb595ebecbbf810 100755 (executable)
@@ -9,7 +9,7 @@ $this->title = 'Создание записи о премии, авансе и 
 $this->params['breadcrumbs'][] = ['label' => 'Персональные премии, авансы и подсчёт ', 'url' => ['index']];
 $this->params['breadcrumbs'][] = $this->title;
 ?>
-<div class="admin-person-bonuses-create">
+<div class="admin-person-bonuses-create m-5">
 
     <h1><?= Html::encode($this->title) ?></h1>
 
index 940b8aec66c7f2de6771c6ce0b82b40bd89b11fb..20031ace25946eee09dce1b5039f9c487a114ee2 100755 (executable)
@@ -16,7 +16,7 @@ use yii_app\records\AdminPersonBonuses;
 $this->title = 'Персональные премии, авансы и подсчёт';
 $this->params['breadcrumbs'][] = $this->title;
 ?>
-<div class="admin-person-bonuses-index">
+<div class="admin-person-bonuses-index m-5">
 
     <h1><?= Html::encode($this->title) ?></h1>
 
index 43e987eabe1dd86d0d22c8dda9d431d49985f93b..eb22c07b59cad5444cdbe7641ba1f934137bc9e9 100755 (executable)
@@ -10,7 +10,7 @@ $this->params['breadcrumbs'][] = ['label' => 'Персональные прем
 $this->params['breadcrumbs'][] = ['label' => $model->id, 'url' => ['view', 'id' => $model->id]];
 $this->params['breadcrumbs'][] = 'Изменмть';
 ?>
-<div class="admin-person-bonuses-update">
+<div class="admin-person-bonuses-update m-5">
 
     <h1><?= Html::encode($this->title) ?></h1>
 
index f3c0669ff09cffac3953200ded33d212a9c471ac..acd456a1918862121f9626107e769d84e4602aa0 100755 (executable)
@@ -11,7 +11,7 @@ $this->params['breadcrumbs'][] = ['label' => 'Персональные прем
 $this->params['breadcrumbs'][] = $this->title;
 \yii\web\YiiAsset::register($this);
 ?>
-<div class="admin-person-bonuses-view">
+<div class="admin-person-bonuses-view m-5">
 
     <h1><?= Html::encode($this->title) ?></h1>
 
@@ -33,6 +33,8 @@ $this->params['breadcrumbs'][] = $this->title;
             'color_ruble_bonuses',
             'vacation_day',
             'retention',
+            'retention_comment',
+            'part_time_job_hours',
             'shift_correction',
             'prepaid_expense',
             'counting',
index f33606633f6343d6493ee9f0a73b1699e26a6783..647e056c3985d4253f0b0b1fda893599475592d7 100755 (executable)
@@ -33,14 +33,11 @@ if (!empty($timetableAdminAnotherStoreById)) {
                     <th>Магазин</th>
                     <th>Число сотрудников в смене</th>
                     <th>Сотрудники смены</th>
-                    <th>Нормы смены магазина</th>
                     <th>Продажи магазина (00:00 - 23:59)</th>
-                    <th>Норма смена сотрудника</th>
                     <th>Сумма продаж сотрудника</th>
                     <th>Число чеков сотрудника</th>
                     <th>Сумма оклада за смену</th>
                     <th>Средний чек магазина</th>
-                    <th>Баллы геймификации</th>
                 </thead>
 
                 <?php
@@ -61,15 +58,12 @@ if (!empty($timetableAdminAnotherStoreById)) {
                         <td><?php echo $item['typeSmena'] ?></td>
                         <td><?php echo $storeName ?></td>
                         <td><?php echo $item['count_admin_store'] ?></td>
-                        <td><?php echo $item['adminNameWithRateList'] ?></td>
-                        <td><?php echo $item['normaSmenaAdminsSumByLevelList'] ?></td>
+                        <td><?php echo $item['adminNameList'] ?></td>
                         <td><?php echo HtmlHelper::getNumberFormat($item['adminsSalesSum']) ?></td>
-                        <td><?php echo HtmlHelper::getNumberFormat($item['normaSmena']['rate_1_condition']) ?></td>
                         <td><?php echo HtmlHelper::getNumberFormat($item['daySale']) ?></td>
                         <td><?php echo $item['countCheckByDay'] ?></td>
                         <td><?php echo HtmlHelper::getNumberFormat($item['wages']) ?></td>
                         <td><?php echo HtmlHelper::getNumberFormat($avgCheckValue) ?></td>
-                        <td><?php echo $item['game']['values_sum'] ?></td>
                     </tr>
                     <?php
                     $key++;
@@ -85,17 +79,13 @@ if (!empty($timetableAdminAnotherStoreById)) {
                     <td></td>
                     <td></td>
                     <td></td>
-                    <td></td>
-                    <td></td>
                     <td><?php echo HtmlHelper::getNumberFormat($wagesAdminAnotherStore[$storeKey]) ?></td>
                     <td></td>
-                    <td></td>
                 </tr>
             </table>
 
         </div>
         <?php
     }?>
-    <h4>Сумма баллов геймификации <?php echo $context ?> : <?php echo $adminSumGameBonus?></h4>
     <?php
 }
diff --git a/erp24/views/cabinet202310/_already_pay_in_month.php b/erp24/views/cabinet202310/_already_pay_in_month.php
new file mode 100644 (file)
index 0000000..a541985
--- /dev/null
@@ -0,0 +1,47 @@
+<?php
+
+/* @var $toPayoff float */
+/* @var $alreadyPay float */
+/* @var $alreadyPaySum float */
+
+use yii_app\helpers\HtmlHelper;
+
+if (!empty($alreadyPay) && !empty($alreadyPaySum)) {
+    ?>
+    <br>
+
+    <b>Таблица выплат за выбранный месяц:</b>
+    <table class=" table table-border">
+        <thead>
+        <th>Название</th>
+        <th>Сумма, руб</th>
+        </thead>
+        <?php
+        foreach ($alreadyPay as $keyName => $value) {
+            ?>
+            <tr>
+            <td><?php echo $keyName ?></td>
+            <td><?php echo HtmlHelper::getNumberFormat($value) ?> </td>
+            </tr><?php
+        }
+        ?>
+        <tfoot>
+        <th></th>
+        <th><?php echo HtmlHelper::getNumberFormat($alreadyPaySum) ?></th>
+        </tfoot>
+
+    </table>
+    <?php
+}
+?>
+
+<?php
+
+if (!empty($toPayoff)) {
+    ?>
+    <br>
+    <b>К выплате</b> за выбранный месяц <b><?php echo HtmlHelper::getNumberFormat($toPayoff) ?> руб</b>
+    <br>
+    <?php
+}
+?>
index 1209e1cf9dc9a0de54bebadeff050bbbb271648c..a56321f1211eb6167d81b8f0af1f0d33d9c4e39d 100755 (executable)
@@ -45,88 +45,13 @@ $ratingBy = 'средниму баллу';
 $endKey = 1;
 
 echo '<br><h4>Персональные показатели</h4>';
-echo '<br> Сумма баллов геймификации : ' . $clusterAdminSumGameBonus;
 
 echo '<br> Число магазинов : ' . $administratorCountInRating;
-echo '<br> Среднее значение баллов геймификации : ' . $clusterAdminAvgSumGameBonus;
 
-if (!empty($ratingPerson)) {
-    echo '<br> Ваш рейтинг по ' . $ratingBy . ' : ' . $ratingPerson . ' из ' . $countRatingList;
-}
 
 $tbl = '';
 
 
 
-if (!empty($ratingList)){
-    $tbl = '';
-
-    $arrayReverseKeys = array_reverse(array_keys($ratingList));
-
-    foreach ($ratingList as $key => $row) {
-        $firstKeys = range(0,$endKey);
-
-        $cssCurrentUser = '';
-        $cssCurrentUserCell = '';
-        if ($clusterAdminId == $row['admin_id']) {
-            $cssCurrentUser = 'table-info';
-            $cssCurrentUserCell = 'bg-orange-lighter';
-        }
-
-        $sortArray = [];
-        foreach ( $firstKeys as $item) {
-            if (array_key_exists($item, $arrayReverseKeys)) {
-                $sortArray[] = $arrayReverseKeys[$item];
-            }
-        }
-
-
-        if ($clusterAdminId == $row['admin_id']) {
-            $cssCurrentUser .= ' border-info';
-        }
-
-        $addText = '';
-            $addText = ' (' . $row['value'] . ' балов/' . $row['administrators_count'] . ' администраторов)';
-
-        $tbl .= "<tr class='" . $cssCurrentUser . "'>
-                        <td>" . $row['rating'] . " </td>
-                        <td>" . $row[$valueKey] . $addText . "</td>
-                        <td  class='" . $cssCurrentUserCell . "'>" . $row['admin']['name_full'] . " </td>
-                    </tr>";
-
-    }
-
-
-        $sumRow = '
-            <tr>
-                <td></td>
-                <td>Сумма баллов ' . $ratingListSum . '</td>
-                <td></td>
-            </tr>
-        ';
-
-
-echo'
-        <div class="block_info">
-            <span class="btn_toggle_block" >показать рейтинг<i class="arrow down"></i></span>
-            <div class="block_body block_body_hide">
-                <table class="salary table table-border">
-                    <thead>
-                        <th>Рейтинг</th>
-                        <th>' . $valueName .  '</th>
-                        <th>Имя</th>
-                    </thead>                    
-
-                    <tbody>
-                        ' . $tbl . '
-                        ' . $sumRow . '
-                    </tbody>
-                </table>
-            </div> 
-        </div>
-                
-        <br>';
-} else {
-    echo '<br> рейтинга нет';
-}
+
 
diff --git a/erp24/views/cabinet202310/_holiday_table_values.php b/erp24/views/cabinet202310/_holiday_table_values.php
new file mode 100755 (executable)
index 0000000..ef5eeff
--- /dev/null
@@ -0,0 +1,209 @@
+<?php
+
+use yii_app\helpers\DataHelper;
+use yii_app\helpers\HtmlHelper;
+
+
+/* @var $consolidatedPremiumByFocusGroups array */
+/* @var $consolidatedArrUsersSalaryCheck array */
+/* @var $consolidatedPremiumByStore float */
+/* @var $onePartHolidayPremium float */
+/* @var $adminsHolidayShiftCount float */
+/* @var $personPremiumByStore float */
+/* @var $personHolidayShiftCount float */
+
+
+$this->registerCssFile('/yii_app/css/common/block-info.css');
+$this->registerJsFile('/yii_app/js/common/block-info.js', ['position' => \yii\web\View::POS_END]);
+
+
+echo '<h4>Блок премирования магазина <br>за продажу фокусных позиций в мартовские праздники</h4>';
+
+
+if (!empty($consolidatedPremiumByFocusGroups)) {
+
+    $fields = [
+        0 => [
+            'name' => ' услуг ',
+            'percentText' => ' 10% ',
+            'keySum' => 'userSalaryServices',
+            'keyPremium' => 'userSalaryServicesPremium',
+            'alias' => 'services',
+            'tableName' => 'продажи услуг',
+        ],
+        1 => [
+            'name' => ' сопутки ',
+            'percentText' => ' 5% ',
+            'keySum' => 'userSalaryRelated',
+            'keyPremium' => 'userSalaryRelatedPremium',
+            'alias' => 'related',
+            'tableName' => 'продажи сопутки',
+        ],
+        2 => [
+            'name' => ' горшечки ',
+            'percentText' => ' 5% ',
+            'keySum' => 'userSalaryPotted',
+            'keyPremium' => 'userSalaryPottedPremium',
+            'alias' => 'potted',
+            'tableName' => 'продажи горшечки',
+        ],
+        3 => [
+            'name' => ' упаковки ',
+            'percentText' => ' 5% ',
+            'keySum' => 'userSalaryWrap',
+            'keyPremium' => 'userSalaryWrapPremium',
+            'alias' => 'wrap',
+            'tableName' => 'продажи упаковки',
+        ],
+        4 => [
+            'name' => ' пиротехники ',
+            'percentText' => ' 5% ',
+            'keySum' => 'userSalarySalut',
+            'keyPremium' => 'userSalarySalutPremium',
+            'alias' => 'salut',
+            'tableName' => 'продажи пиротехники',
+        ],
+        5 => [
+            'name' => ' не фокусных товаров ',
+            'percentText' => ' 1% ',
+            'keySum' => 'userSalaryOtherItems',
+            'keyPremium' => 'userSalaryOtherItemsPremium',
+            'alias' => 'other_items',
+            'tableName' => 'продажи не фокусных товаров',
+        ],
+    ];
+
+    foreach ($fields as $field) {
+        if (!empty($consolidatedPremiumByFocusGroups[$field['keySum']])) {
+            echo '<br> Факт продаж ' . $field['name'] . ' : ' . HtmlHelper::getNumberFormat($consolidatedPremiumByFocusGroups[$field['keySum']]) . ' руб';
+            echo '<br> Премия за продажу ' . $field['name'] . ' ' . $field['percentText'] . '  : ' . HtmlHelper::getNumberFormat($consolidatedPremiumByFocusGroups[$field['keyPremium']]) . ' руб';
+
+            echo $this->render('_table_salary_checks', [
+                'arrUsersSalary' => $consolidatedArrUsersSalaryCheck[$field['alias']],
+                'tableName' => $field['tableName'],
+                'userSalarySum' => $consolidatedPremiumByFocusGroups[$field['keySum']],
+                'sellerShow' => true,
+            ]);
+
+        } else {
+            echo '<br> Факта продажи ' . $field['name'] . ' нет<br>';
+        }
+    }
+
+    if (!empty($consolidatedPremiumByFocusGroups['userSalaryPremiumSum'])) {
+        echo '<br><h5>Сумма премии магазина за продажу фокусных позиций  <b>' . HtmlHelper::getNumberFormat($consolidatedPremiumByFocusGroups['userSalaryPremiumSum']) . ' руб </b></h5>';
+    }
+
+}
+
+/**/
+
+$textInfoMatrix = ' 2% ';
+
+if (!empty($consolidatedPremiumByMatrix) && !empty($consolidatedPremiumByMatrix['salesMatrix'])) {
+
+    echo"<br>";
+    echo"<h4>Продажи букетов по матрице за праздники по магазину</h4>";
+    echo"<h5>Проданные букеты по матрице за праздники</h5>";
+
+    $tbl = '';
+
+    foreach ($consolidatedPremiumByMatrix['salesMatrix'] as $row) {
+        $tbl .= "<tr><td>" . $row["date"] . " </td><td>" . $row["admin_name"] . " </td><td>" . $row["operation"] . " </td><td>  " . $row["number"] . " </td><td>  " . $row["product_name"] . " </td><td>  " . HtmlHelper::getNumberFormat($row["summ"]) . " </td><td>" . HtmlHelper::getNumberFormat($row["bonus"]) . " </td></tr>";
+    }
+
+    echo'
+        <div class="block_info">
+            <span class="btn_toggle_block" >показать список<i class="arrow down"></i></span>
+            <div class="block_body block_body_hide">
+                <table class="salary table table-border">
+                    <thead>
+                        <th>Дата</th>
+                        <th>Сотрудник</th>
+                        <th>Операция</th>
+                        <th>Название чека</th>
+                        <th>Букет</th>
+                        <th>Сумма</th>
+                        <th>Бонус</th>
+                    </thead>
+                    <tbody>' . $tbl . '</tbody>
+                </table>
+                <p class="p-3">
+                    <span>Число чеков ' . count($consolidatedPremiumByMatrix['salesMatrix']) . '</span>
+                </p>
+            </div> 
+            <br>
+            <div>
+                    Сумма продаж матрицы ' . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['salaryMatrix']) . ' руб * ' . $textInfoMatrix . ' = ' . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['bonusSalaryMatrix']) . '  руб
+            </div>
+        </div>
+                
+        <br>';
+} else {
+    echo '<br> Продаж по матрице нет';
+}
+
+echo"<h5>Собранные букеты по матрице за праздники</h5>";
+
+if (!empty($consolidatedPremiumByMatrix) && !empty($consolidatedPremiumByMatrix['makeMatrix'])) {
+
+    $tbl2 = '';
+
+    foreach ($consolidatedPremiumByMatrix['makeMatrix'] as $row) {
+        $tbl2 .= "<tr><td>" . $row["date"] . " </td><td>" . $row["admin_name"] . " </td><td>" . $row["operation"] . " </td><td>  " . $row["number"] . " </td><td>  " . $row["product_name"] . " </td><td>  " . HtmlHelper::getNumberFormat($row["summ"]) . " </td><td>" . HtmlHelper::getNumberFormat($row["bonus"]) . " </td></tr>";
+    }
+
+    echo'
+            <div class="block_info">
+                <span class="btn_toggle_block" >показать список<i class="arrow down"></i></span>
+                <div class="block_body block_body_hide">
+                    <table class="salary table table-border">
+                        <thead>
+                            <th>Дата</th>
+                            <th>Сотрудник</th>
+                            <th>Операция</th>
+                            <th>Название чека</th>
+                            <th>Букет</th>
+                            <th>Сумма</th>
+                            <th>Бонус</th>
+                        </thead>
+                        <tbody>' . $tbl2 . '</tbody>
+                    </table>
+                    <p class="p-3">
+                        <span>Число чеков ' . count($consolidatedPremiumByMatrix['makeMatrix']) . '</span>
+                    </p>
+                </div> 
+                <br>
+                <div>
+                        Сумма продаж собранных букетов матрицы ' . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['salaryMakeMatrix']) . ' руб * ' . $textInfoMatrix . ' = ' . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['bonusMakeMatrix']) . '  руб
+                </div>
+            </div>
+                
+            <br>';
+} else {
+    echo '<b>Собранных букутов нет</b> <br>';
+}
+
+if (!empty($consolidatedPremiumByMatrix['matrixPrime'])) {
+    echo '<br><h5>Сумма премии магазина за матрицу: <b>' . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['matrixPrime']) . ' руб </b></h5>';
+}
+
+
+
+echo '<br><h5>Сумма премии магазина за продажу фокусных позиций и матрицы </h5>';
+echo '<div>'
+    . HtmlHelper::getNumberFormat($consolidatedPremiumByFocusGroups['userSalaryPremiumSum'] ?? 0) .
+    ' руб  + '
+    . HtmlHelper::getNumberFormat($consolidatedPremiumByMatrix['matrixPrime'] ?? 0) .
+    ' руб = ' . HtmlHelper::getNumberFormat($consolidatedPremiumByStore) . ' руб </div>';
+echo '<br><h5>Общая сумма премии магазина: <b>' . HtmlHelper::getNumberFormat($consolidatedPremiumByStore) . ' руб </b></h5>';
+echo '<br><h5>Число смен сотрудников, работающих в праздники: ' . DataHelper::ruPlural($adminsHolidayShiftCount, ['смена', 'смены', 'смен']) . '</h5>';
+echo '<br><h5>Премия за одну смену: ' . HtmlHelper::getNumberFormat($onePartHolidayPremium) . ' руб</h5>';
+echo '<br><h5>В праздники вы отработали: ' . DataHelper::ruPlural($personHolidayShiftCount, ['смену', 'смены', 'смен']) . '</h5>';
+echo '<br><h5>Ваша часть премии за продажу фокусных позицый в праздники: <b>' . HtmlHelper::getNumberFormat($personPremiumByStore) . ' руб</b></h5>';
+echo '<br>';
+echo '<br>';
+echo '<br>';
+
+
+/**/
\ No newline at end of file
index e2c070783ca4ab8067f313ccc42bcf3ba6a0b6ca..2d3d4744b4f000cd93afc8c451251e2f6dd27d84 100755 (executable)
@@ -44,8 +44,16 @@ if (!empty($employeeSelect["d_id"]) && array_key_exists($employeeSelect["d_id"],
 }
 ?>
 <?php
+$monthlySalaryRow = null;
+if (!empty($administratorOklad) && $isAdministrator) {
+    $monthlySalaryRow = HtmlHelper::getNumberFormat($administratorOklad);
+}
 if (!empty($monthlySalary) && array_key_exists('monthly_salary', $monthlySalary) && !$isAdministrator) {
-    echo "<br> <b>Оклад : " . HtmlHelper::getNumberFormat($monthlySalary['monthly_salary']) . " руб.</b>";
+    $monthlySalaryRow = HtmlHelper::getNumberFormat($monthlySalary['monthly_salary']);
+}
+
+if (!empty($monthlySalaryRow)) {
+    echo "<br> <b>Оклад : " . $monthlySalaryRow . " руб.</b>";
 }
 ?>
 
index 7dbbfd6eb59c5bbabeeec76ede52c1f06d8217db..9602612b36a3c97dff1d794b1f46f60870ef104d 100755 (executable)
@@ -68,6 +68,10 @@ $endKey = ($isAdministrator) ? 2 : 4;
 echo " <h3>Сумма продаж по первому блоку премирования </h3>";
 echo '<br><h4>Первый блок премирования: продажа фокусных позиций</h4>';
 
+if (!empty($showHolidayVersion)) {
+    echo '<p><b>Премии за продажу фокусных позиций в мартовские праздники (с 05.03.2024 по 08.03.2024 ) <br> в Блоке премирования магазина</b></p>';
+}
+
 $tbl = '';
 
 
@@ -273,6 +277,14 @@ if (!empty($teamBonus)) {
         'teamBonus' => $teamBonus,
     ]);
 }
+if (!empty($adminTeamPayrollTable)) {
+    echo '<br>';
+
+    echo $this->render('_table_team_payroll', [
+        'teamBonus' => $teamBonus,
+        'adminTeamPayrollTable' => $adminTeamPayrollTable,
+    ]);
+}
 
 echo '<h5>Командная премия : ' . HtmlHelper::getNumberFormat($teamBonusValue) . ' руб</h5>';
 
index e6ccf279059a6bfdbdd85c18ecff7bc98f943706..fa869bc199dc97a90bfc00db57e54d7ca5aadd81 100644 (file)
@@ -5,6 +5,7 @@
 /* @var $arrUsersSalary array */
 /* @var $userSalarySum float */
 /* @var $tableName string */
+/* @var $sellerShow bool */
 
 use yii_app\helpers\HtmlHelper;
 
@@ -15,21 +16,37 @@ if (!empty($arrUsersSalary)) {
     $tbl = '';
 
     foreach ($arrUsersSalary as $row) {
-        $tbl .= "<tr><td>" . $row["date"] . " </td><td>" . $row["operation"] . " </td><td>  " . $row["number"] . " </td><td>" . HtmlHelper::getNumberFormat($row["bonus"]) . " </td></tr>";
+        $tbl .= "<tr><td>" . $row["date"] . " </td>";
+        if ($sellerShow) {
+            $tbl .= "<td>" . $row["name"] . " </td>";
+        }
+        $tbl .= "<td>" . $row["operation"] . " </td><td>  " . $row["number"] . " </td><td>" . HtmlHelper::getNumberFormat($row["bonus"]) . " </td></tr>";
     }
-    $tbl .= "<tr><td></td><td></td><td></td><td>" . HtmlHelper::getNumberFormat($userSalarySum) . " </td></tr>";
+
+    $tbl .= "<tr>
+                <td></td><td></td><td></td>";
+    if ($sellerShow) {
+        $tbl .= "<td></td>";
+    }
+    $tbl .= "<td>" .HtmlHelper::getNumberFormat($userSalarySum) . " </td></tr>";
+
+    $tblHeader = "<thead>
+                        <th>Дата</th>
+                    ";
+    if ($sellerShow) {
+        $tblHeader .= "<th>Продавец</th>";
+    }
+    $tblHeader .= "    <th>Операция</th>
+                       <th>Название</th>
+                       <th>Сумма руб.</th>
+                   </thead>";
 
     echo'
         <div class="block_info">
             <span class="btn_toggle_block" >показать список ' . $tableName . '<i class="arrow down"></i></span>
             <div class="block_body block_body_hide">
                 <table class="salary table table-border">
-                    <thead>
-                        <th>Дата</th>
-                        <th>Операция</th>
-                        <th>Название</th>
-                        <th>Сумма руб.</th>
-                    </thead>
+                    ' . $tblHeader . '
                     <tbody>' . $tbl . '</tbody>
                 </table>
             </div> 
diff --git a/erp24/views/cabinet202310/_table_team_payroll.php b/erp24/views/cabinet202310/_table_team_payroll.php
new file mode 100755 (executable)
index 0000000..2258c11
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+
+
+/* @var $winStoreIdDayChallenge array */
+/* @var $cityStoreNames array */
+/* @var $adminTeamPayrollTable array */
+/* @var $teamBonus array */
+
+use yii\helpers\ArrayHelper;
+
+$this->registerCssFile('/yii_app/css/common/block-info.css');
+$this->registerJsFile('/yii_app/js/common/block-info.js', ['position' => \yii\web\View::POS_END]);
+
+if (!empty($adminTeamPayrollTable)) {
+
+    $tbl = '';
+//
+//    'adminPayDayAll'
+//'payrollVariableDaysAll'
+    /*
+     * $result[$admin['id']]['admin_id'] = $admin['id'];
+                $result[$admin['id']]['admin_name'] = $admin['name'];
+                $result[$admin['id']]['group_name'] = $admin['group_name'];
+                $daysRow = [];
+
+                foreach ($days as $day) {
+                    $keyAdminIdDateRow = $admin['id'] . '_' . $day;
+                    $payConstantRow = 0;
+                    if (array_key_exists($keyAdminIdDateRow, $teamBonusAdminPayDayAll)) {
+                        $payConstantRow = ArrayHelper::getValue($teamBonusAdminPayDayAll, $keyAdminIdDateRow);
+                    }
+                    $payVariableRow = 0;
+
+                    if (array_key_exists($keyAdminIdDateRow, $teamBonusPayrollVariableDaysAll)) {
+                        $payVariableRow = ArrayHelper::getValue($teamBonusPayrollVariableDaysAll, $keyAdminIdDateRow);
+                    }
+                    $daysRow[$day] = [
+                        'pay_constant' => $payConstantRow,
+                        'pay_variable' => $payVariableRow,
+                    ];
+     * */
+
+    foreach ($adminTeamPayrollTable as $key => $row) {
+//        $storeIdKey =array_key_first($row);
+//        $rowValue = $row[array_key_first($row)];
+
+
+        $tbl .= "<tr>";
+        $tbl .= "<td>" . $row['admin_name'] . " </td><td>" . $row['group_name'] . " </td>";
+
+        foreach ($row['days'] as $keyDay => $rowDayValue) {
+            $rowPayConstant = $rowDayValue['pay_constant'] ?? '-';
+            $rowPayVariable = $rowDayValue['pay_variable'] ?? '-';
+            $tbl .= "<td>" . $rowPayConstant . "  </td><td> " . $rowPayVariable . " </td>";
+        }
+
+        $tbl .= "</tr>";
+    }
+
+    $days = $teamBonus['days'] ?? [];
+    $tblHead = "<tr>";
+    $tblHead .= "<td>Сотрудник</td>";
+    $tblRowTwo = "<tr><td>Дата</td>";
+    foreach ($adminTeamPayrollTable as $key => $row) {
+
+        $tblHead .= "<td colspan='2'>" . $row['admin_name'] . " (" . $row['group_name'] . ") </td>";
+
+        $tblRowTwo .= "<td>Оклад</td>";
+        $tblRowTwo .= "<td>Премия</td>";
+
+    }
+    $tblRowTwo .= "<tr>";
+    $tblHead .= "</tr>";
+
+    $tblRow = "";
+    foreach ($days as $day) {
+        $tblRow .= "<tr>";
+        $tblRow .= "<td>" . $day . "</td>";
+        foreach ($adminTeamPayrollTable as $key => $row) {
+
+
+            if (!empty($row['days'][$day])) {
+                $rowDayValue = $row['days'][$day];
+                $rowPayConstant = $rowDayValue['pay_constant'] ?? '-';
+                $rowPayVariable = $rowDayValue['pay_variable'] ?? '-';
+                $tblRow .= "<td>" . $rowPayConstant . "</td>";
+                $tblRow .= "<td>" . $rowPayVariable . "</td>";
+            }
+        }
+
+        $tblRow .= "</tr>";
+
+    }
+
+
+
+    echo'
+        <div class="block_info">
+            <span class="btn_toggle_block" >Оклады и премии магазина в командном бонусе<i class="arrow down"></i></span>
+            <div class="block_body block_body_hide">
+                <div class="table-responsive">
+                    <table class="table table-bordered">
+                        <thead>
+                            ' . $tblHead . '
+                            ' . $tblRowTwo . '
+                        </thead>
+                        <tbody>
+                            ' . $tblRow . '
+                        </tbody>
+                    </table>
+                </div>
+            </div> 
+            <br>
+        </div>
+                
+        <br>';
+} else {
+    echo '<br> <br> <b>Нет данных</b> <br>';
+}
\ No newline at end of file
index 8cb47ba115c1e05c292e223af00b7f3b089ff263..91e5084e4f011cddef4bb33f010c8128580bc79e 100755 (executable)
@@ -153,6 +153,30 @@ use yii_app\forms\dashboard\DaysSearchForm;
 /* @var $sumColumnWages float */
 /* @var $teamBonusValue float */
 /* @var $teamBonus array */
+/* @var $adminTeamPayrollTable array */
+
+
+/* @var $personRetention float */
+/* @var $personRetentionArray array */
+/* @var $sumPersonRetention float */
+
+/* @var $personPrepaidExpense float */
+/* @var $toPayoff float */
+/* @var $alreadyPay float */
+/* @var $alreadyPaySum float */
+
+/* @var $allowShowPersonRetention bool */
+
+/* @var $showHolidayVersion bool */
+
+/* @var $consolidatedArrUsersSalaryCheck array */
+/* @var $consolidatedPremiumByFocusGroups array */
+/* @var $consolidatedPremiumByMatrix array */
+/* @var $consolidatedPremiumByStore float */
+/* @var $onePartHolidayPremium float */
+/* @var $adminsHolidayShiftCount float */
+/* @var $personPremiumByStore float */
+/* @var $personHolidayShiftCount float */
 
 
 
@@ -198,6 +222,7 @@ $this->params['breadcrumbs'][] = $this->title;
         'normalCostShift' => $normalCostShift,
         'monthNameSelect' => $monthNameSelect,
         'yearSelect' => $yearSelect,
+        'administratorOklad' => $administratorOklad,
     ]); ?>
 
     <?php
@@ -272,9 +297,26 @@ $this->params['breadcrumbs'][] = $this->title;
         'userQualityPremium' => $userQualityPremium,
         'teamBonus' => $teamBonus,
         'teamBonusValue' => $teamBonusValue,
+        'adminTeamPayrollTable' => $adminTeamPayrollTable,
+        'showHolidayVersion' => $showHolidayVersion
     ]);
     ?>
 
+    <?php
+    if ($showHolidayVersion) {
+        echo $this->render('_holiday_table_values', [
+            'consolidatedArrUsersSalaryCheck' => $consolidatedArrUsersSalaryCheck,
+            'consolidatedPremiumByFocusGroups' => $consolidatedPremiumByFocusGroups,
+            'consolidatedPremiumByMatrix' => $consolidatedPremiumByMatrix,
+            'consolidatedPremiumByStore' => $consolidatedPremiumByStore,
+            'onePartHolidayPremium' => $onePartHolidayPremium,
+            'adminsHolidayShiftCount' => $adminsHolidayShiftCount,
+            'personPremiumByStore' => $personPremiumByStore,
+            'personHolidayShiftCount' => $personHolidayShiftCount,
+        ]);
+    }
+    ?>
+
     <?php
     if (!empty($salaryByAdmin)) {
         echo "<b><h3> Продажи " . HtmlHelper::getNumberFormat($salaryByAdmin) . " руб </h3></b> ";
@@ -413,4 +455,47 @@ echo "<br><br>";
     <br>
     <h4>Сумма окладов и премий за выбранный период <b><?php echo HtmlHelper::getNumberFormat($allTotalAdministrator) ?> руб</b></h4>
 
+
+    <?php
+
+    if (!empty($personRetention)) {
+        ?>
+        <br>
+
+        <b>Таблица персональных вычетов за выбранный месяц:</b>
+        <table class=" table table-border">
+            <thead>
+            <th>Название</th>
+            <th>Сумма, руб</th>
+            </thead>
+            <?php
+            foreach ($personRetentionArray as $keyName => $value) {
+                ?>
+                <tr>
+                <td><?php echo $keyName ?></td>
+                <td><?php echo HtmlHelper::getNumberFormat($value) ?> </td>
+                </tr><?php
+            }
+            ?>
+            <tfoot>
+            <th></th>
+            <th><?php echo HtmlHelper::getNumberFormat($sumPersonRetention) ?></th>
+            </tfoot>
+
+        </table>
+        <?php
+    }
+    ?>
+
+    <?php
+    if (!empty($allowShowPersonRetention)) {
+        echo $this->render('_already_pay_in_month', [
+            'toPayoff' => $toPayoff,
+            'alreadyPay' => $alreadyPay,
+            'alreadyPaySum' => $alreadyPaySum,
+        ]);
+    }
+    ?>
+    <br>
+
     <?php echo $this->render('_disclaimer_info'); ?>
\ No newline at end of file
index 937aa76ec17b9f7885fb5cbb9e24ad797cdea83f..495b18ed191a6e4ebf6e5bd5e1a6c8d39e77e20f 100755 (executable)
@@ -262,29 +262,6 @@ $this->params['breadcrumbs'][] = $this->title;
     }
     ?>
 
-    <?php
-    echo $this->render('_cluster_personal_values', [
-//        'adminSumGameBonus' => $adminSumGameBonus,
-        'ratingPerson' => $ratingPerson,
-        'ratingList' => $ratingList,
-        'ratingListSum' => $ratingListSum,
-        'countRatingList' => $countRatingList,
-//        'adminSumGameCountShift' => $adminSumGameCountShift,
-//        'adminSumGameAvgSum' => $adminSumGameAvgSum,
-        'clusterAdminId' => $clusterAdminId,
-//        'adminSumGameBonusTotal' => $adminSumGameBonusTotal,
-//        'adminSumGameCountShiftTotal' => $adminSumGameCountShiftTotal,
-//        'adminSumGameAvgSumTotal' => $adminSumGameAvgSumTotal,
-
-
-        'clusterAdminSumGameBonus' => $clusterAdminSumGameBonus,
-        'clusterAdminAvgSumGameBonus' => $clusterAdminAvgSumGameBonus,
-        'administratorCountInRating' => $administratorCountInRating,
-    ]);
-    ?>
-
-    <br>
-
     <?php ;
     echo "<hr>";
     ?>
index db04b8eace61870234e40f571f4753961a6c1307..1f3f07c8d9b9695b743e5707f8b56fe662fdc448 100755 (executable)
@@ -137,6 +137,29 @@ use yii_app\forms\dashboard\DaysSearchForm;
 /* @var $teamBonusValue float */
 /* @var $teamBonus array */
 
+
+/* @var $personRetention float */
+/* @var $personRetentionArray array */
+/* @var $sumPersonRetention float */
+
+/* @var $personPrepaidExpense float */
+/* @var $toPayoff float */
+
+/* @var $alreadyPay float */
+/* @var $alreadyPaySum float */
+
+/* @var $allowShowPersonRetention bool */
+/* @var $showHolidayVersion bool */
+
+/* @var $consolidatedArrUsersSalaryCheck array */
+/* @var $consolidatedPremiumByFocusGroups array */
+/* @var $consolidatedPremiumByMatrix array */
+/* @var $consolidatedPremiumByStore float */
+/* @var $onePartHolidayPremium float */
+/* @var $adminsHolidayShiftCount float */
+/* @var $personPremiumByStore float */
+/* @var $personHolidayShiftCount float */
+
 $cabinetName = 'Кабинет флориста';
 
 if ($person) {
@@ -279,8 +302,23 @@ $this->params['breadcrumbs'][] = $this->title;
         'userQualityPremium' => $userQualityPremium,
         'teamBonus' => $teamBonus,
         'teamBonusValue' => $teamBonusValue,
+        'showHolidayVersion' => $showHolidayVersion
     ]);
     ?>
+    <?php
+    if ($showHolidayVersion) {
+        echo $this->render('_holiday_table_values', [
+                'consolidatedArrUsersSalaryCheck' => $consolidatedArrUsersSalaryCheck,
+                'consolidatedPremiumByFocusGroups' => $consolidatedPremiumByFocusGroups,
+                'consolidatedPremiumByMatrix' => $consolidatedPremiumByMatrix,
+                'consolidatedPremiumByStore' => $consolidatedPremiumByStore,
+            'onePartHolidayPremium' => $onePartHolidayPremium,
+            'adminsHolidayShiftCount' => $adminsHolidayShiftCount,
+            'personPremiumByStore' => $personPremiumByStore,
+            'personHolidayShiftCount' => $personHolidayShiftCount,
+        ]);
+    }
+    ?>
 
     <?php
     if (!empty($salaryByAdmin)) {
@@ -356,9 +394,52 @@ if (!empty($sumValuesFlorist)) {
     <?php
 }
 ?>
+
 <br>
 <h4>Сумма окладов и премий за выбранный период <b><?php echo HtmlHelper::getNumberFormat($allTotalFlorist) ?> руб</b>
 </h4>
 
+
+<?php
+
+if (!empty($personRetention)) {
+    ?>
+    <br>
+
+    <b>Таблица персональных вычетов за выбранный месяц:</b>
+    <table class=" table table-border">
+        <thead>
+        <th>Название</th>
+        <th>Сумма, руб</th>
+        </thead>
+        <?php
+        foreach ($personRetentionArray as $keyName => $value) {
+            ?>
+            <tr>
+            <td><?php echo $keyName ?></td>
+            <td><?php echo HtmlHelper::getNumberFormat($value) ?> </td>
+            </tr><?php
+        }
+        ?>
+        <tfoot>
+        <th></th>
+        <th><?php echo HtmlHelper::getNumberFormat($sumPersonRetention) ?></th>
+        </tfoot>
+
+    </table>
+    <?php
+}
+?>
+
+<?php
+if (!empty($allowShowPersonRetention)) {
+    echo $this->render('_already_pay_in_month', [
+            'toPayoff' => $toPayoff,
+            'alreadyPay' => $alreadyPay,
+            'alreadyPaySum' => $alreadyPaySum,
+    ]);
+}
+?>
+    <br>
 <?php echo $this->render('_disclaimer_info'); ?>
 
index ecb4da80a2bb0c83edda44267462911625173843..2ae85d7e945030082e88bbd93e75a656f7fc6e4f 100644 (file)
@@ -12,6 +12,9 @@ use yii\widgets\Pjax;
 
 $this->title = 'Магазины';
 $this->params['breadcrumbs'][] = $this->title;
+
+$this->registerJsFile('/js/city-store/index.js', ['position' => \yii\web\View::POS_END]);
+
 ?>
 <div class="city-store-index">
 
@@ -54,6 +57,15 @@ $this->params['breadcrumbs'][] = $this->title;
 //            'content:ntext',
 //            'email:email',
 //            'tg_chat_id',
+            [
+                'label' => 'Телеграм Чат',
+                'format' => 'raw',
+                'value' => function ($model) {
+                    return !empty($model->tg_chat_id) ?
+                        Html::button($model->tg_chat_id, ['class' => 'btn btn-link btn-sm', 'onclick' => 'setTgDialog("' . $model->id . '", "' . $model->tg_chat_id . '");']) :
+                        Html::button('Настроить', ['class' => 'btn btn-success btn-sm', 'onclick' => 'setTgDialog("' . $model->id . '", "' . $model->tg_chat_id . '");']);
+                }
+            ],
 //            'h1',
 //            'sprav_id',
 //            'images:ntext',
index 91774a716b4d598df9686e7d60e8d49190b6e836..ac3f00cd3cd8716b0008a54a4dab58f4c1513ca8 100755 (executable)
@@ -1,5 +1,6 @@
 <?php
 
+use kartik\select2\Select2;
 use yii\helpers\Html;
 use yii\widgets\ActiveForm;
 
@@ -22,9 +23,22 @@ use yii\widgets\ActiveForm;
             <?= $form->field($model, 'id') ?>
         </div>
         <div class="col-4">
-            <?= $form->field($model, 'admin_id')->dropDownList(\yii_app\records\Admin::find()->select(['name', 'id'])->indexBy('id')->column(), [
-                    'prompt' => '---',
-            ]) ?>
+            <?php
+            $adminsWithGroup = \yii_app\records\Admin::find()->select(['name', 'id'])->indexBy('id')->orderBy('name' , SORT_DESC)->all();
+            $admins = [];
+            foreach ($adminsWithGroup as $key => $item) {
+                $admins[$key] = $item['name'] . ' (' . $item['id'] . ')';
+
+            }
+
+            echo $form->field($model, 'admin_id')->widget(Select2::class, [
+                'data' => $admins,
+                'language' => 'ru',
+                'options' => ['placeholder' => '---'],
+                'pluginOptions' => [
+                    'allowClear' => true,
+                ]
+            ])?>
         </div>
         <div class="col-4">
             <?= $form->field($model, 'admin_group_id')->dropDownList(\yii_app\records\AdminGroup::find()->select(['name', 'id'])->indexBy('id')->column(), [
index e5b7fae90b3819afe8bf8297bcb0c7d167561a51..d36989844d08dcf703cedba4d9593ea5bc90a302 100755 (executable)
@@ -11,7 +11,6 @@
  * @var $number
  * @var $city_stores
  * @var $store_traffik
- * @var $sales_products
  * @var $equal_days
  * @var $arr_work
  * @var $date_timetable
@@ -31,7 +30,6 @@
  * @var $productsArrayServices
  * @var $servises
  * @var $saleServices
- * @var $checkSellerDiscount
  * @var $daysSearchForm
  * @var \yii\web\View $this
  */
diff --git a/erp24/views/info_table/cabinet.php b/erp24/views/info_table/cabinet.php
new file mode 100644 (file)
index 0000000..5aab325
--- /dev/null
@@ -0,0 +1,8 @@
+<?php
+
+$this->registerCssFile('/yii_app/css/infoTable/cabinet.css');
+$this->registerJsFile('/yii_app/js/infoTable/cabinet.js', ['position' => \yii\web\View::POS_END]);
+
+?>
+    <h1>Кабинет</h1>
+<div class="text-row">f8tg9yhujomip,mkonjihbu</div>
\ No newline at end of file
index 2f9c62f88e85150665755a74bc137ff23688e94b..749bb73659b4eb8949dd376adfecf0ecbf742b92 100644 (file)
@@ -60,7 +60,7 @@ use yii_app\helpers\PrintBlockHelper;
             ]
         ])->label(false)); ?>
 
-<?php/*
+<? /*
     <?php PrintBlockHelper::printBlock('Статусы групп уроков', $filterForm->field($filterModel, 'lesson_group_status')
         ->widget(Select2::class, [
             'data' => $lessonGroupStatuses,
index 07406e7e817abd64c6a4b12289ef185c569864d9..6f697670e867312a6717002dde1a9750210c0ca4 100644 (file)
@@ -44,6 +44,7 @@ use yii_app\services\FileService;
     ?>
     </div>
     <div class="form-group">
+        <span>Доступна загрузка изображения только в формате jpg и png !</span>
     <?= $form->field($modelMatrixErpProperty, 'imageFile')->fileInput(['accept' => 'image/*', 'extension' => ['png','jpg']])->label(false) ?>
     </div>
 
index f16c1b6e997a0da2037dce33d69948fc5fafe4d0..4d595ce1b054138888b2f3445525ce3646f5be43 100755 (executable)
@@ -21,6 +21,7 @@ use yii_app\helpers\HtmlHelper;
 /* @var $yearSelect string */
 /* @var $monthSelect string */
 /* @var $dateToCabinet string */
+/* @var $lastPacketDate string */
 /* @var $allowedPayrollUpdate bool */
 /* @var $yearMonthSearchForm yii_app\forms\payroll\YearMonthSearchForm */
 
index a0a9926f860595a80d599978921feb6a62cbd7ad..8f775c7aad34a5c79c3c992292d95d7db6fe596b 100755 (executable)
@@ -14,7 +14,7 @@ use yii_app\records\SchedulerTaskLog;
 $this->title = 'Scheduler Task Logs';
 $this->params['breadcrumbs'][] = $this->title;
 ?>
-<div class="scheduler-task-log-index">
+<div class="scheduler-task-log-index p-8">
 
     <h1><?= Html::encode($this->title) ?></h1>
 
@@ -24,35 +24,58 @@ $this->params['breadcrumbs'][] = $this->title;
 
     <?php Pjax::begin(); ?>
     <?php // echo $this->render('_search', ['model' => $searchModel]); ?>
+    <div class="table-responsive">
+        <?= GridView::widget([
+            'dataProvider' => $dataProvider,
+            'filterModel' => $searchModel,
+            'columns' => [
+                ['class' => 'yii\grid\SerialColumn'],
 
-    <?= GridView::widget([
-        'dataProvider' => $dataProvider,
-        'filterModel' => $searchModel,
-        'columns' => [
-            ['class' => 'yii\grid\SerialColumn'],
-
-            'id',
-            'task_num',
-            'date_start',
-            'date_stop',
-            'name',
-            'alias',
-            'description:ntext',
-            'result:ntext',
-            'result_number',
-            'error:ntext',
-            'info:ntext',
-            'log:ntext',
-            'date',
-            [
-                'class' => ActionColumn::className(),
-                'urlCreator' => function ($action, SchedulerTaskLog $model, $key, $index, $column) {
-                    return Url::toRoute([$action, 'id' => $model->id]);
-                 }
-            ],
-        ],
-    ]); ?>
+                'id',
+                //'task_num',
+                'date_start',
+                'date_stop',
+                [
+                    'attribute' => 'status',
+                    'value' => function (SchedulerTaskLog $model) {
+                        if ($model->date_start != null && $model->date_stop != null) {
+                            return 'Выполнено';
+                        }
 
+                        return 'Пропущенно';
+                    },
+                    'filter' => \kartik\select2\Select2::widget([
+                        'model' => $searchModel,
+                        'attribute' => 'status',
+                        'data' => $searchModel->statusArray
+                    ])
+                ],
+                'name',
+                //'alias',
+                //'description:ntext',
+                //'result:ntext',
+                //'result_number',
+                'error:ntext',
+                'info:ntext',
+                [
+                    'attribute' => 'log',
+                    'value' => function (SchedulerTaskLog $model) {
+                        return strlen($model->log) > 400 ? mb_substr($model->log, 0, 400) . "..." : $model->log;
+                    },
+                    'contentOptions' => [
+                            'class' => 'w-25'
+                    ]
+                ],
+                'date',
+                [
+                    'class' => ActionColumn::className(),
+                    'urlCreator' => function ($action, SchedulerTaskLog $model, $key, $index, $column) {
+                        return Url::toRoute([$action, 'id' => $model->id]);
+                    }
+                ],
+            ],
+        ]); ?>
+    </div>
     <?php Pjax::end(); ?>
 
 </div>
diff --git a/erp24/views/shipment/division-print-edit.php b/erp24/views/shipment/division-print-edit.php
new file mode 100644 (file)
index 0000000..72e0f05
--- /dev/null
@@ -0,0 +1,491 @@
+<?php
+
+use yii\base\DynamicModel;
+use yii\widgets\ActiveForm;
+use kartik\select2\Select2;
+
+use yii_app\helpers\PrintBlockHelper;
+
+/* @var $storeAll array */
+/* @var $products array */
+/* @var $colorsCnt array */
+/* @var $quantity_warehouseman_fact array */
+/* @var $orderId string */
+/* @var $productsMinLot array */
+/* @var $dataFieldsValues array */
+/* @var $storeGroups array */
+/* @var $filterModel DynamicModel */
+/* @var $division_name string */
+/* @var $division_date string */
+/* @var $products_colors array */
+/* @var $dataColor array */
+/* @var $dataHand array */
+
+$this->registerJsFile('/yii_app/js/shipment/division-print-edit.js', ['position' => \yii\web\View::POS_END]);
+
+$storeGroupOptions = [-1 => 'Не выбран'];
+foreach ($storeGroups as $gIndex) {
+    $storeGroupOptions[$gIndex] = $gIndex;
+}
+
+$printOrientationOptions = [
+    'portrait' => 'Портретная',
+    'landscape' => 'Альбомная',
+];
+
+?>
+
+<div class="m-5">
+    <h5 class="page-title mb-0 text-primary">Деление по магазинам <?= $division_name ?> Дата деления <?= $division_date ?> id=<?= $orderId ?></h5>
+    <?php $filterForm = ActiveForm::begin(['id' => 'filter-form']); ?>
+        <div class="row">
+            <div class="col-1 text-right">Печатать цвет:</div>
+            <div class="col-1"><?= $filterForm->field($filterModel, 'printColor')->checkbox(['value' => 1, 'uncheckValue' => 0,
+                    'onclick' => '$("#filter-form").get(0).submit();'], false)->label(false) ?></div>
+            <div class="col-2 text-right">Печатать ручных добавок:</div>
+            <div class="col-1"><?= $filterForm->field($filterModel, 'printHand')->checkbox(['value' => '1', 'uncheckValue' => '0',
+                    'onclick' => '$("#filter-form").get(0).submit();'], false)->label(false) ?></div>
+            <div class="col-2 text-right">Показать столбцы итого:</div>
+            <div class="col-1"><?= $filterForm->field($filterModel, 'printSumm')->checkbox(['value' => '1', 'uncheckValue' => '0',
+                    'onclick' => '$("#filter-form").get(0).submit();'], false)->label(false) ?></div>
+        </div>
+        <?php PrintBlockHelper::printBlock('Выберите куст', $filterForm->field($filterModel, 'groupIndex')->widget(Select2::class, [
+            'data' => $storeGroupOptions,
+            'language' => 'ru',
+            'options' => ['placeholder' => 'Куст...'],
+            'pluginOptions' => [
+                'allowClear' => true,
+            ],
+            'pluginEvents' => [
+                'change' => 'function(e) {
+                    $("#filter-form").get(0).submit();
+                }'
+            ],
+        ])->label(false)); ?>
+        <?php PrintBlockHelper::printBlock('Ориентация', $filterForm->field($filterModel, 'printOrientation')->widget(Select2::class, [
+            'data' => $printOrientationOptions,
+            'language' => 'ru',
+            'options' => ['placeholder' => 'Ориентация...'],
+            'pluginOptions' => [
+                'allowClear' => true,
+            ],
+            'pluginEvents' => [
+                'change' => 'function(e) {
+                    $("#filter-form").get(0).submit();
+                }'
+            ],
+        ])->label(false)); ?>
+    <?php ActiveForm::end() ?>
+    <div class="col-1">
+        <button id="shipmentPrintButton" class="btn btn-primary btn-lg" onclick="printTable();">Print</button>
+    </div>
+    <div class="table-responsive">
+        <table class="table-hover zak">
+            <thead>
+                <tr class="zg">
+                    <th class="td_product">наименование</th>
+                    <th><b>мин-ый лот деления шт.</b></th>
+                    <?php foreach($storeAll as $store): ?>
+                        <?php if ($filterModel->groupIndex == -1 || $store->parent_id == $filterModel->groupIndex): ?>
+                            <th><b><?= $store->name ?></b></th>
+                            <?php if ($filterModel->groupIndex != -1): ?>
+                                <th style="min-width: 40px"></th>
+                            <?php endif; ?>
+                        <?php endif; ?>
+                    <?php endforeach; ?>
+                    <th><b>итого</b></th>
+                    <th><b>куплено</b></th>
+                    <th><b>разница</b></th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php
+                    $colorsCounter = [];
+                    $ostatok = [];
+                ?>
+                <?php foreach($products as $productId => $productName): ?>
+                    <?php if (!empty($colorsCnt[$productId]) and $quantity_warehouseman_fact[$productId]["NULL"]["NULL"] > 0): ?>
+                        <tr id="tr__<?= $productId ?>" class="trproduct">
+                            <td class="td_product producted">
+                                <span class="fs-6">
+                                    <a href="/shipment/divisionPrintEditProduct/?productId=<?= $productId ?>&id=<?= $orderId ?>"
+                                       target=new><?= $productName ?></a>
+                                </span>
+                            </td>
+                            <td><?= $productsMinLot[$productId] ?></td>
+                            <?php $divisionCnt = 0; ?>
+                            <?php foreach($storeAll as $store): ?>
+                                <?php
+                                    $value = ceil($dataFieldsValues[$productId][$store->id]["NULL"] ?? 0);
+                                    $ostatok[$productId][$store->id] = $value;
+                                    $divisionCnt += $value;
+                                    if (empty($value)) {
+                                        $value = "";
+                                    }
+                                ?>
+                                <?php if ($filterModel->groupIndex == -1 || $store->parent_id == $filterModel->groupIndex): ?>
+                                    <td>
+                                        <?= $value ?>
+                                        <?php if (!empty($dataHand[$productId][$store->id]['NULL']) && $filterModel->printHand == 1): ?>
+                                            <sup style="color:green; font-size:0.5rem"><?= intval($dataHand[$productId][$store->id]["NULL"]) ?></sup>
+                                        <?php endif; ?>
+                                    </td>
+                                    <?php if ($filterModel->groupIndex != -1): ?>
+                                        <td style="min-width: 40px"></td>
+                                    <?php endif; ?>
+                                <?php endif; ?>
+                            <?php endforeach; ?>
+                            <td><?= intval($divisionCnt) ?></td>
+                            <td><?= intval($quantity_warehouseman_fact[$productId]["NULL"]["NULL"]) ?></td>
+                            <?php $r2 = $quantity_warehouseman_fact[$productId]["NULL"]["NULL"] - $divisionCnt; ?>
+                            <td <?= ($r2 != 0 ? 'class="bg-danger"' : '') ?> ><?= $r2 ?></td>
+                        </tr>
+                    <?php endif; ?>
+                    <?php if ($filterModel->printColor == 1): ?>
+                        <?php if (!empty($products_colors[$productId])): ?>
+                            <?php foreach($products_colors[$productId] as $colorName): ?>
+                                <?php
+                                    $colorName = trim($colorName);
+                                    $colorAllCnt = 0;
+                                ?>
+                                <?php if (!empty($dataColor[$productId][$colorName])): ?>
+                                    <tr>
+                                        <td class="tr"><?= $colorName ?>(<?= $dataColor[$productId][$colorName] ?> шт.)</td>
+                                        <td></td>
+                                        <?php
+                                            $colorsCounter[$productId]++;
+                                            $newHand = [];
+                                        ?>
+                                        <?php foreach($storeAll as $store): ?>
+                                            <?php if ($filterModel->groupIndex == -1 || $store->parent_id == $filterModel->groupIndex): ?>
+                                                <?php
+                                                    $value = ceil($dataFieldsValues[$productId][$store->id][$colorName] ?? 0);
+                                                    $ostatok[$productId][$store->id] -= $value;
+                                                    $colorAllCnt += $value;
+                                                ?>
+                                                <td <?= $value % ($productsMinLot[$productId] ?? 1) != 0 ? 'class="bg-danger"' : '' ?>
+                                                        onclick="ShowInput('division_hand',
+                                                                '<?= $store->id ?>',
+                                                                '<?= $productId ?>',
+                                                                '<?= $colorName ?>',
+                                                                '<?= md5($colorName) ?>',
+                                                                '<?= $productsMinLot[$productId] ?>',
+                                                                '<?= $value ?>')"
+                                                    id="division_hand<?= $store->id ?><?= $productId ?><?= md5($colorName) ?>" >
+                                                    <?= $value ?>
+                                                </td>
+                                                <?php if ($filterModel->groupIndex != -1): ?>
+                                                    <td style="min-width: 40px"></td>
+                                                <?php endif; ?>
+                                            <?php endif; ?>
+                                        <?php endforeach; ?>
+                                        <?php if ($filterModel->printSumm == 1): ?>
+                                            <?php $difColor = $dataColor[$productId][$colorName] - $colorAllCnt; ?>
+                                            <td><?= $colorAllCnt ?></td>
+                                            <td><?= $dataColor[$productId][$colorName] ?></td>
+                                            <td <?= $difColor != 0 ? 'class="bg-danger"' : '' ?>><?= $difColor ?></td>
+                                        <?php endif; ?>
+                                    </tr>
+                                <?php endif; ?>
+                            <?php endforeach; ?>
+                        <?php endif; ?>
+                        <?php if (!empty($colorsCounter[$productId])): ?>
+                        <tr class="bg-success">
+                            <td class="tr">остаток</td>
+                            <td></td>
+                            <?php foreach($storeAll as $store): ?>
+                                <?php if ($filterModel->groupIndex == -1 || $store->parent_id == $filterModel->groupIndex): ?>
+                                    <?php $value = $ostatok[$productId][$store->id]; ?>
+                                    <td <?= $value < 0 ? 'class="bg-danger"' : '' ?> ><?= $value ?></td>
+                                    <?php if ($filterModel->groupIndex != -1): ?>
+                                        <td style="min-width: 40px"></td>
+                                    <?php endif; ?>
+                                <?php endif; ?>
+                            <?php endforeach; ?>
+                            <?php if ($filterModel->printSumm == 1): ?>
+                                <td></td>
+                                <td></td>
+                                <td class="bg-danger"></td>
+                            <?php endif; ?>
+                        </tr>
+                    <?php endif; ?>
+                    <?php endif; ?>
+                    <?php if (!empty($colorsCnt[$productId]) and $quantity_warehouseman_fact[$productId]["NULL"]["NULL"] > 0): ?>
+                        <?php if ($filterModel->groupIndex == -1): ?>
+                            <tr class="trproduct">
+                                <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                                <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                                <?php foreach($storeAll as $store): ?>
+                                    <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                                <?php endforeach; ?>
+                                <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                                <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                                <td class="td_product"><span class="fs-6">&nbsp;</span></td>
+                            </tr>
+                        <?php endif; ?>
+                    <?php endif; ?>
+                <?php endforeach; ?>
+            </tbody>
+        </table>
+    </div>
+</div>
+
+<script>
+    function printTable() {
+        const landscape = '<?= $filterModel->printOrientation ?>' === 'landscape';
+        const css = '@page { ' + (landscape ? 'size: landscape;' : '') + ' margin: 0;  } #shipmentPrintButton, #filter-form {display: none;}' +
+            'a[href]:after { content: "" !important;}',
+            head = document.head || document.getElementsByTagName('head')[0],
+            style = document.createElement('style');
+
+        style.media = 'print';
+        style.appendChild(document.createTextNode(css));
+
+        head.appendChild(style);
+
+        window.print();
+
+        head.removeChild(style)
+    }
+</script>
+
+<style>
+    table tbody tr td {
+        border: 3px solid black !important;
+    }
+
+    table.table tbody tr:hover td {
+        background: #cdcdcd
+    }
+
+    .zak tbody tr:hover td {
+        background: #cdcdcd
+    }
+
+    .zak > thead > tr > th, .zak tr.zg th, .zak tr.zg td {
+        font-size: 0.7rem;
+        min-width: 30px;
+        text-align: center;
+        font-weight: normal;
+        max-height: 60px;
+        overflow: hidden
+    }
+
+    .zak > thead > tr > th b {
+        font-weight: normal;
+    }
+
+    .zak > :not(caption) > * > * {
+        padding: 0.05rem;
+        box-shadow: none;
+    }
+
+    .zak td.fs-5 {
+        text-align: left;
+        padding: 0.3rem 1rem;
+    }
+
+    .zak {
+        border-collapse: collapse;
+        border-spacing: 0;
+        overflow: hidden;
+    }
+
+    .zak th, .zak td {
+        border: 1px solid #e6e6e6;
+        padding: 0.1rem;
+        vertical-align: middle;
+        position: relative;
+    }
+
+    .zak td:hover:before {
+        background-color: #e3e3e3;
+        content: '';
+        height: 100%;
+        left: -5000px;
+        position: absolute;
+        top: 0;
+        width: 10000px;
+        z-index: -2;
+    }
+
+    .zak td:hover:after {
+        background-color: #cdcdcd;
+        content: '';
+        height: 10000px;
+        left: 0;
+        position: absolute;
+        top: -5000px;
+        width: 100%;
+        z-index: -1;
+    }
+
+    .zak tbody td input.form-control {
+        font-size: 0.8rem;
+        min-width: 70px;
+        max-width: 100px;
+        font-weight: bold;
+        border: 0;
+        border-radius: 0;
+        color: #333;
+        padding: 0.2rem;
+        margin: 0;
+    }
+
+    .zak tbody td input.form-control:focus {
+        border: 2px #cd0202 solid;
+        background: #ffccdb
+    }
+
+    .zak td.bg-danger, .zak td.bg-indigo, .zak td.bg-info, .zak tr th.bg-danger, .zak tr th.bg-info, .zak tr th.bg-indigo {
+        color: #fff;
+    }
+
+    table.zak thead th:not(:first-child), table.zak tr.zg th th:not(:first-child) {
+        vertical-align: bottom;
+        line-height: normal;
+    }
+
+    table.zak thead b {
+        writing-mode: vertical-rl;
+        transform: scale(-1);
+    }
+
+    table.zak tr.zg th b, table.zak tr.zg td b {
+        writing-mode: vertical-rl;
+        transform: scale(-1);
+        font-weight: normal;
+        font-size: 0.6rem;
+    }
+
+    .zak tr th .th_p_summ {
+        text-align: center;
+        font-weight: bold;
+    }
+
+    .app-content .side-app {
+        padding: 25px 0.5rem 0 0.5rem;
+    }
+
+    .zak tbody tr td.td_product, .zak td.td_product {
+        tex-align: left;
+    }
+
+    .zak td.td_product:hover {
+        background: #fff;
+    }
+</style>
+<style>
+    .zak tbody tr:hover:not(.no-hover) td {
+        background: #cdcdcd
+    }
+
+    .zak > thead > tr > th, .zak tr.zg th {
+        font-size: 0.7rem;
+        min-width: 30px;
+        max-width: 40px;
+        text-align: center;
+        font-weight: normal;
+        overflow: hidden
+    }
+
+    .zak > thead > tr > th b, .zak > thead > tr > td b {
+        font-weight: normal;
+    }
+
+    .zak > :not(caption) > * > * {
+        padding: 0.05rem;
+        box-shadow: none;
+    }
+
+    .zak td.fs-5 {
+        text-align: left;
+        padding: 0.3rem 1rem;
+    }
+
+    .zak {
+        border-collapse: collapse;
+        border-spacing: 0;
+        overflow: hidden;
+    }
+
+    .zak th, .zak td {
+        border: 1px solid #e6e6e6;
+        padding: 0.1rem;
+        vertical-align: middle;
+        position: relative;
+    }
+
+    table.zak thead th, table.zak tr.zg th th, table.zak tr.zg td td {
+        vertical-align: bottom;
+        line-height: normal;
+    }
+
+    table.zak thead b, table.zak tbody b {
+        writing-mode: vertical-rl;
+        transform: scale(-1);
+    }
+
+    table.zak tr.zg th b, table.zak tr.zg td b {
+        writing-mode: vertical-rl;
+        transform: scale(-1);
+        font-weight: normal;
+        font-size: 0.6rem;
+    }
+
+    .app-content .side-app {
+        padding: 25px 0.5rem 0 0.5rem;
+    }
+
+    .zak tbody tr td.td_product, .zak td.td_product {
+        text-align: right;
+    }
+
+    .zak td.td_product:hover {
+        background: #fff;
+    }
+
+    .zak tr td.pr, .zak tr td.ost {
+        text-align: center;
+    }
+
+    .zak tr td.pr {
+        background: #ddd
+    }
+
+    .zak tr td.ost {
+        background: #e6e6e6
+    }
+
+    .zak td {
+        text-align: center;
+        vertical-align: bottom;
+    }
+
+    .zak td.lf {
+        text-align: left;
+        background: #fff
+    }
+
+    .zak td.tr {
+        text-align: right;
+    }
+
+    .zak td, .zak thead th {
+        color: #000;
+    }
+
+    .zak tr.trproduct td {
+        font-size: 1rem;
+        font-weight: bold;
+    }
+
+    input.greener {
+        border: 2px green solid;
+    }
+
+    input.editColor {
+        width: auto;
+        max-width: 70px;
+    }
+</style>
diff --git a/erp24/views/shipment/fields-data.php b/erp24/views/shipment/fields-data.php
new file mode 100644 (file)
index 0000000..6a85f32
--- /dev/null
@@ -0,0 +1,592 @@
+<?php
+
+
+use yii\grid\ActionColumn;
+use yii\helpers\Url;
+use yii\helpers\Html;
+use yii\grid\GridView;
+use yii\widgets\Pjax;
+use yii_app\records\Dashboard;
+use yii_app\records\StoreOrdersFields;
+use yii_app\records\StoreOrdersStatuses;
+use yii_app\records\StoreOrderStatus;
+use yii_app\services\ShipmentService;
+
+/* @var $this yii\web\View */
+/* @var $bonusConversionCost int */
+
+/* @var $userSalarySalut float */
+/* @var $userSalarySalutPremium float */
+/* @var $storeOrders array */
+/* @var $dozakupka array */
+/* @var $store_orders_statuses array */
+/* @var $dataStoreOrdersFields array */
+/* @var $dostupFields array */
+/* @var $bgFields array */
+/* @var $orders_status_description array */
+/* @var $adminGroups array */
+/* @var $urlActionPart string */
+/* @var $orderId string */
+/* @var $groupId int */
+/* @var $userGroup string */
+/* @var $orderData array */
+/* @var $storeOrderStatusDescription string */
+/* @var $storeOrderStatus string */
+/* @var $storeId ?int */
+/* @var $status_order_id int */
+/* @var $status_edit_dostup array */
+/* @var $store_orders_status_description array */
+/* @var $storesArray array */
+/* @var $storeArr array */
+/* @var $store_orders_statuses array */
+/* @var $statuses_stores_show array */
+/* @var $products_varieties array */
+/* @var $products_class array */
+/* @var $products array */
+/* @var $productsOptions array */
+/* @var $productsColorsArray array */
+/* @var $prov array */
+/* @var $statuses_dostup array */
+/* @var $dostup_fields array */
+/* @var $bg_fields array */
+/* @var $fieldsRows array */
+/* @var $dataTableHeader array */
+/* @var $shipmentService object */
+
+$this->title = 'Заказ товара';
+$this->params['breadcrumbs'][] = $this->title;
+$modul = 'shipment';
+
+
+
+$this->registerCssFile('/yii_app/css/table/table.css', ['position' => \yii\web\View::POS_END]);
+
+?>
+
+
+    <div class="index">
+
+        <h1><?= Html::encode($this->title) ?></h1>
+
+
+
+
+    </div>
+    <div class="alert alert-warning" role="alert"><a href="/shipments/index" class="btn me-2 btn-info">❮ назад в закупки</a>
+
+
+
+    <a href="https://youtu.be/Ol0mWDFYKsw" class="btn me-2 btn-danger" target=new>видео-инструкция новый интерфейс 2</a>
+    <a href="https://youtu.be/4sGW2MqDMgM" class="btn me-2 btn-danger" target=new>видео2</a>
+
+
+    Описание статуса: <?php echo $storeOrderStatusDescription ?>  Под кем будем просматривать
+<?php
+foreach ($adminGroups as $gid => $nameGroup) {
+
+    $buttonStyle = '';
+    $urlRow = '/shipment/' . $urlActionPart .'/?id=' . $orderId . '&group_id=' . $gid;
+    
+    if ($gid == $groupId) {
+        $buttonStyle = 'btn-success';
+    } else {
+        $buttonStyle = 'btn-outline-info';
+    }
+    
+    ?><a href='<?= $urlRow?>' class='m-1 btn btn-sm <?php echo $buttonStyle;?>'><?php echo $nameGroup; ?></a><?php
+
+}
+?>
+
+
+<br>
+<?php
+?>
+
+
+        Дата старта продаж (от этой даты считаем продажи при авто-заказе) <?php echo $orderData['date_start']; ?>
+        Дата деления (от этой даты считаем продажи при делении)<?php echo $orderData['division_date']; ?>
+
+
+
+
+<!--<a href="/shipment/' . $urlActionPart . '/?id=' . $orderId . '&insert=1" class="btn btn-danger me-2">1) подгрузить данные из старого интерфейса</a>-->
+<span onclick="ajaxUpdateFieldsDataTest();" class="btn btn-info me-2">1) TEST!!! поссчитать статистические данные данные</span>
+<span onclick="ajaxUpdateFieldsData();" class="btn btn-info me-2">1) поссчитать статистические данные данные</span>
+<span onclick="ajaxUpdateStep();" class="btn btn-indigo me-2">2) обновить остаток склада</span>
+<span onclick="foreachSalesHand();" class="btn btn-warning me-2"> 3) обновить с распределене остатков склада по ячейкам добавка вручную</span>
+<span onclick="ajaxUploadAutoPurchase();" class="btn btn-warning me-2">автозаказ общий обновить</span>
+
+
+
+
+<span onclick="deleteAll();" class="btn btn-danger me-2">!!!очистить все данные из нового интерфейса!!</span>
+
+
+
+</div>
+
+<a href="/shipment/<?php echo $urlActionPart;?>/?id=<?php echo $orderId ?>'&update=1" class="btn btn-info me-2">обновить данные в таблице</a>
+
+
+<h1 class="page-title mb-0 text-primary">Заказ товара <?php echo $orderData["name"] ?> id=<?php echo $orderId ?>
+<span class="btn btn-lime"><?php echo  $storeOrderStatus ?></span>  ваша роль <b> <?php echo $userGroup ?></b></h1>';
+
+<?php
+// панель с магазинами
+ShipmentService::showOrderStoresPanel(
+    $status_order_id,
+    $status_edit_dostup,
+    $store_orders_status_description,
+    $storesArray,
+    $storeArr,
+    $storeId,
+    $store_orders_statuses,
+    $statuses_stores_show,
+    $urlActionPart,
+    $orderId,
+    $groupId
+);
+
+//если статус новый то вносим цены по товарам в нужые столбцы - розничная цена
+if (!empty($status_order_id) && $status_order_id == 1) {
+
+
+    ?><a href=\"/shipment/$urlActionPart/?id=$orderId&group_id=$gid&load=purchase_price\" class=\"btn btn-danger me-2\">загрузить розничные цены</a><?php
+
+
+    if (!empty($_REQUEST["load"])) {
+        $data = $db::getRows("SELECT product_id, price FROM `prices` WHERE product_id $whereInProductsId");
+        foreach ($data as $row) {
+            $productsPrices[$row["product_id"]] = $row["price"];
+        }
+        $data_uper = [];
+        foreach ($products as $productId => $nameProduct) {
+            echo "<br>$nameProduct Роз. цена=" . $productsPrices[$productId] . "  закуп " . $productsOptions[$productId]["price_zakup"] . " ";
+            $price = $productsPrices[$productId];
+            $data_uper[$productId]["NULL"]["NULL"] = $price;
+
+            $db::sql("
+                UPDATE 
+                    `store_orders_prices` 
+                SET purchase_price='$price'
+                WHERE 
+                    product_id='$productId' 
+                AND 
+                    order_id='$orderId' 
+                AND 
+                    provider_id=1 
+                AND 
+                    purchase_price!='0.00'"
+            );
+
+        }
+
+//розничная цена
+        insert_store_orders_fields($data_uper, "purchase_price");
+
+
+        $data_uper = [];
+        foreach ($products as $productId => $nameProduct) {
+            $price = $productsOptions[$productId]["price_zakup"];
+            $data_uper[$productId]["NULL"]["NULL"] = $productsOptions[$productId]["price_zakup"];
+            $db::sql("UPDATE `store_orders_prices` SET purchase_price_zakup='$price'
+WHERE product_id='$productId' AND order_id='$orderId' AND provider_id=1 AND purchase_price_zakup!='0.00'");
+        }
+        insert_store_orders_fields($data_uper, "purchase_price_zakup");
+
+//header("Location: /shipment/$urlActionPart/?id=$orderId&group_id=$gid");
+    }
+
+
+}
+
+
+//если выбран магазин то
+if (!empty($store_id)) echo '<input type=hidden name=store_id_id value=' . $store_id . ' id=store_id_id>';
+
+echo '
+<div id=edit_div></div>
+<div class="table-responsive mt-3">
+    <table class="zak">';
+$html = '<thead>
+            <tr class="zg">
+                <th class="text-right">наименование <span onclick="$(\'.trcolors\').toggle();" class="btn btn-sm btn-warning">раскрыть цвета</span>
+
+                    <span onclick="$(\'.sorts_flowers\').toggle();" class="btn btn-sm btn-warning">показать сорта</span>
+
+
+<a href="/shipment/statusFieldsSort/?status_id=' . $status_order_id . '" target=new class="btn btn-sm btn-secondary">сортировка столбцов</a>
+
+<a href="/shipment/config/?status_id=' . $status_order_id . '" target=new class="btn btn-sm btn-grey">настройка столбцов</a>
+
+
+</th>';
+$thead = $html; // формируем thead
+$head_td = $html;
+
+
+
+$rowArraySum = [];
+$shipmentService->rowArraySum = [];
+
+
+if (!empty($groupId)) {
+    foreach ($dataStoreOrdersFields as $row) {
+        $dostup = $dostup_fields[$row["id"]];
+        $bg = $bg_fields[$row["id"]];
+        if ($dostup == "edit" or $dostup == "show") {
+
+
+            $html = '<th class="text-center" data-bs-placement="top" data-bs-toggle="tooltip" data-bs-original-title="' . $row["name_full"] . ' ' . $row["name_eng"] . '"  onclick="ajaxFieldInfo(' . $row["id"] . ')" style="max-width:90px;">
+    <b>' . $row["name"] . '</b></th>';
+            $thead .= $html;
+            $head_td .= $html;
+        }
+
+    }
+}
+
+$thead .= '</tr></thead>';
+$head_td .= '</tr>';
+echo '' . $thead . '<tbody>';
+
+
+//$FiledsData=getDataFiledsData();
+
+
+// полнограммы по всем магазинам
+if (!empty($store_id)) {
+    $data3 = $db::getRows("SELECT store_id,product_id,quantity FROM store_planogram WHERE color='' 
+AND store_id!='' AND quantity>0 AND store_id=?", [$store_id]);
+    foreach ($data3 as $row2) $store_planogramAllStores[$row2["store_id"]][$row2["product_id"]] = $row2["quantity"];
+}
+
+//$data3 = $db::getRows("SELECT * FROM products_class WHERE tip in ('potted','wrap')");
+//$data3 = ProductsClass::find()->andWhere(['tip' => array('potted','wrap')])->asArray()->all();
+
+
+
+
+$trCount = 0;
+foreach ($products as $pid => $name) {
+    if ($trCount == 20) {
+        $trCount = 0;
+        echo $head_td;
+    }
+    $trCount++;
+
+    echo '<tr';
+
+
+    if (!empty($store_id) and empty($store_planogramAllStores[$store_id][$pid])) {
+        echo ' class="bg-danger"';
+    }
+
+
+    if (empty($FiledsData["quantity_warehouseman_fact"][$pid]["NULL"]["NULL"]) and $status_order_id >= 6) {
+//        echo ' class="bg-danger"';
+//
+//        echo ' style="opacity:0.5"';
+    }
+
+
+    echo '><td class="text-right">';
+//если статус общий то группируем по магазинам
+    if (empty($statuses_stores_show[$status_order_id])) {
+        echo '<span onclick="$(\'.trstores_' . $pid . '\').toggle();" class="btn btn-default btn-sm">+</span>';
+    }
+    echo '' . $name . '';
+
+
+//узнаем категорибю товара
+    $categoryId = $productsOptions[$pid]["parent_id"];
+    $tip = '';
+// по категории узнаем тип товара горшечка или упаковка
+    if (!empty($products_class[$categoryId])) {
+        $tip = $products_class[$categoryId];
+    }
+
+
+    if (array_key_exists($pid, $productsColorsArray)) {
+        if (count($productsColorsArray[$pid]) > 0) {
+            echo '<span onclick="$(\'.trcolors_' . $pid . '\').toggle();" class="btn btn-sm btn-success">+ цвета</span>';
+        }
+    }
+    echo '<input type=hidden name=provider_id[' . $pid . '] value="' . $prov[$pid] . '">';
+    echo '</td>';
+
+
+//    if (!empty($store_id)) {
+        foreach ($dataStoreOrdersFields as $row) {
+            $shipmentService->printFieldTd($row["name_eng"], $pid, null);
+        }
+//    }
+
+    echo '</tr>';
+
+
+//begin colors
+    if (array_key_exists($pid, $productsColorsArray)) {
+        foreach ($productsColorsArray[$pid] as $color) {
+            $color = trim($color);
+            if (!empty($color)) {
+                echo '<tr class="trcolors trcolors_' . $pid . ' bg-gray-300" style="display:none;"><td class="text-right">' . $name . ' + <span class="btn btn-sm btn-warning me-1">' . $color . '</span>';
+
+                if (!empty($products_varieties[$pid][$color])) {
+                    echo '<div class="sorts_flowers" style="display:none;"><br>сорта ';
+                    foreach ($products_varieties[$pid][$color] as $k => $var) {
+                        echo "<span class=\"btn btn-sm btn-outline-info me-1\">$var</span>";
+                    }
+                    echo '</div>';
+                }
+
+
+
+                if (!empty($store_id) && !empty($color)) {
+                    foreach ($dataStoreOrdersFields as $row) {
+//                        printFieldTd($row["name_eng"], $pid, null, null);
+                        $shipmentService->printFieldTd($row["name_eng"], $pid, $store_id, $color);
+                    }
+                }
+
+                echo "</tr>";
+            }
+
+        }
+    }
+//end colors
+
+
+}
+
+
+echo '<tr class="bg-success zg"><td class="text-right"></td>';
+foreach ($dataStoreOrdersFields as $row) {
+    $dostup = $dostup_fields[$row["id"]];
+    $bg = $bg_fields[$row["id"]];
+    if ($dostup == "edit" or $dostup == "show") {
+        echo '<td class="text-center" title="' . $row["name_full"] . ' ' . $row["name_eng"] . '"><b>' . $row["name"] . ' (' . $fieldsRows[$row["name_eng"]]["row_type_sum"] . ')</b></td>';
+    }
+}
+echo '</tr>
+<tr class="bg-success"><td class="text-right">итого -ГО</td>';
+foreach ($dataStoreOrdersFields as $row) {
+    $dostup = $dostup_fields[$row["id"]];
+    if ($dostup == "edit" or $dostup == "show") {
+        $s = "";
+        if ($fieldsRows[$row["name_eng"]]["row_type_sum"] == "amount") {
+            $s = $shipmentService->rowArraySum[$row["id"]] ?? 0;
+        }
+        if ($fieldsRows[$row["name_eng"]]["row_type_sum"] == "avg") {
+            if (!empty($shipmentService->rowArraySum["cnt__" . $row["id"]])) {
+                $s = round($shipmentService->rowArraySum[$row["id"]] ?? 0 / $shipmentService->rowArraySum["cnt__" . $row["id"]]);
+            }
+        }
+
+        echo '<td class="text-center ' . $bg . '"><b>' . $s . '</b></td>';
+    }
+}
+echo '</tr></tbody>';
+echo '</table>
+
+<style>table tr td.bg-lime{background:lime;color:#fff;}</style>';
+/*
+$db::sql("DELETE FROM  store_orders_fields_data WHERE  field_name='division_auto_need_all' AND order_id='$orderId'");
+
+// суммируем деление и заносим данные в таблицу хранения данных по полям
+foreach($products as $productId => $name) {
+//echo"<br>$name ";
+  $all=0;
+  $division_auto_need_all=0;
+  foreach($storesArrayAll as $storeId => $nameStore) {
+  //  echo"<br> <b>$nameStore</b>division_auto_need= ".$FiledsData["division_auto_need"][$productId][$storeId]["NULL"]." ";
+   // $summ=$FiledsData["division_auto_need"][$productId][$storeId]["NULL"] + $FiledsData["division_hand"][$productId][$storeId]["NULL"];
+    $all =$all+$summ;
+    $division_auto_need_all += $FiledsData["division_auto_need"][$productId][$storeId]["NULL"];
+  //  if(!empty($summ)) { $data_uper=[];$data_uper[$productId][$storeId]["NULL"]=$summ;insert_store_orders_fields($data_uper,"division_summ");}
+
+
+  }
+
+$field_name="division_auto_need_all";
+//echo" Итого деления потребность + $division_auto_need_all = ".$FiledsData[$field_name][$productId]["NULL"]["NULL"]." division_auto_need_all=$division_auto_need_all ";
+if(!empty($division_auto_need_all)) {
+   $FiledsData["division_auto_need_all"][$productId]["NULL"]["NULL"]=$division_auto_need_all;
+    $data_uper=[];$data_uper[$productId]["NULL"]["NULL"]=$division_auto_need_all;insert_store_orders_fields($data_uper,"division_auto_need_all");}
+
+
+}
+
+//пробегаемся по всем продуктам
+foreach($products as $productId => $name) {
+
+
+$division_auto_need_all=$FiledsData["division_auto_need_all"][$productId]["NULL"]["NULL"];
+$quantity_warehouseman_fact=$FiledsData["quantity_warehouseman_fact"][$productId]["NULL"]["NULL"];
+
+
+echo"<br><b>$name</b>  division_auto_need_all=".$FiledsData["division_auto_need_all"][$productId]["NULL"]["NULL"]."
+Сумма потребности =".$division_auto_need_all."
+Сумма получаено по факту  ".$quantity_warehouseman_fact."";
+
+$division_ratio=1;
+if($division_auto_need_all > $quantity_warehouseman_fact) {
+$division_ratio=round($quantity_warehouseman_fact/$division_auto_need_all,2);
+
+echo"<font color=red>-меньше!</font>";
+
+echo" применяем коэффициент $division_ratio = ".$FiledsData["division_ratio"][$productId]["NULL"]["NULL"]." ";
+
+}
+
+$data_uper=[];$data_uper[$productId]["NULL"]["NULL"]=$division_ratio;
+insert_store_orders_fields($data_uper,"division_ratio");
+
+
+}
+
+*/
+
+
+echo "<script>
+function ajaxFieldInfo(id){
+ $('#modal-7 .modal-body').html('Загружаем....');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('');  
+ $.ajax({
+       url: '/shipments/ajaxFieldInfo/',
+       method: 'post',       
+       dataType: 'html',        
+       data: {id: id},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}); 
+}
+
+function ajaxUpdateFieldsDataTest(){
+ $('#modal-7 .modal-body').html('Test Считаем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Обновляем данные');  
+ $.ajax({
+       url: '/shipments/ajax-update-fields-data-test/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: '2', update:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+
+function ajaxUpdateFieldsData(){
+ $('#modal-7 .modal-body').html('Считаем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Обновляем данные');  
+ $.ajax({
+       url: '/shipments/ajaxUpdateFieldsData/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: $orderId, update:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+
+
+function ajaxUpdateStep(){
+ $('#modal-7 .modal-body').html('Считаем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Обновляем данные');  
+ $.ajax({
+       url: '/shipments/ajaxUpdateStep/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: $orderId, update_step:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+
+
+function ajaxUploadAutoPurchase(){
+ $('#modal-7 .modal-body').html('Считаем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Обновляем данные');  
+ $.ajax({
+       url: '/shipments/ajaxUploadAutoPurchase/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: $orderId, update_step:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+
+function foreachSalesHand(){
+ $('#modal-7 .modal-body').html('Считаем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Обновляем данные');  
+ $.ajax({
+       url: '/shipments/ajaxUpdateStep/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: $orderId, update_step:'1', foreachSalesHand:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+
+
+function deleteAll(){
+ const result = confirm('Удаляем данные?');
+    
+    if (result) {
+
+ $('#modal-7 .modal-body').html('Удаляем данные');
+jQuery('#modal-7').modal('show', {backdrop: 'static'}); $('#modal-7 .modal-title').text('Удаляем данные');  
+ $.ajax({
+       url: '/shipments/ajaxUpdateStep/',
+       method: 'post',       
+       dataType: 'html',        
+       data: { id: $orderId, deleteAll:'1'},  
+       success: function(data){  
+    $('#modal-7 .modal-body').html(data);
+       }}) 
+}
+}
+
+
+</script>";
+
+echo '<!-- MODAL -->
+               <div class="modal fade" id="modal-7">
+                       <div class="modal-dialog  modal-lg modal-dialog-centered text-center" role="document">
+                               <div class="modal-content">
+                                       <div class="modal-header">
+                                               <h6 class="modal-title">Описание поля</h6><button aria-label="Close" class="btn-close" data-bs-dismiss="modal" type="button"><span aria-hidden="true">&times;</span></button>
+                                       </div>
+                                       <div class="modal-body p-0">
+                               
+                                       </div>
+                       
+                               </div>
+</div>
+</div>';
+
+
+//include "templates/bottom.php";
+
+
+
+
+
+
+
+
+
+
+
+/*
+
+--
+
+
+
+--
+
+
+ */
\ No newline at end of file
old mode 100644 (file)
new mode 100755 (executable)
index e1ea7f1..9c2ece4
@@ -1,5 +1,120 @@
 <?php
 
-chdir(__DIR__ . '/../../');
 
-include 'modul/shipment/index.php';
\ No newline at end of file
+use yii\grid\ActionColumn;
+use yii\helpers\Url;
+use yii\helpers\Html;
+use yii\grid\GridView;
+use yii\widgets\Pjax;
+use yii_app\records\Dashboard;
+
+/* @var $this yii\web\View */
+/* @var $bonusConversionCost int */
+
+/* @var $userSalarySalut float */
+/* @var $userSalarySalutPremium float */
+/* @var $storeOrders array */
+/* @var $dozakupka array */
+/* @var $store_orders_statuses array */
+
+$this->title = 'Список закупок';
+$this->params['breadcrumbs'][] = $this->title;
+$modul = 'shipments';
+
+?>
+
+
+<div class="dashboard-index">
+
+    <h1><?= Html::encode($this->title) ?></h1>
+
+
+    <p>
+        <?= Html::a('Создать', ['create'], ['class' => 'btn btn-success']) ?>
+    </p>
+
+
+
+</div>
+<?php
+
+foreach($storeOrders as $row) {
+    ?>
+    <div class="expanel expanel-default">
+        <div class="expanel-heading">
+
+            <span class="btn btn-white btn-light me-1"  onclick="$('#external__<?php echo $row["id"]?>').toggle();">показать дозакупки</span>
+            <a href=/<?php echo $modul?>/fields-data/?id=<?php echo $row["id"]?> class="btn btn-default fs-5">
+                <span class="btn btn-outline-info"><?php echo $row["id"]?></span> <?php echo $row["name"]?></a>
+
+
+            <div class="d-inline-block dropdown me-2">
+                <button type="button" class="btn bg-dark-transparent dropdown-toggle"  onclick="$(this).parent().children('.dropdown-menu').toggle();">действия</button>
+                <div class="dropdown-menu" style="display:none;">
+                    <a class="dropdown-item" href="/shipment/add/?id=<?php echo $row["id"]?>">правка</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/view/?id=<?php echo $row["id"]?>>старый интерфейс</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/view2/?id=<?php echo $row["id"]?>>новый интерфейс</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/fields-data/?id=<?php echo $row["id"]?> >новый интерфейс2</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/division/?id=<?php echo $row["id"]?>>деление</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/purchase/?id=<?php echo $row["id"]?>>цвета для кустовых при заказе</a>
+
+                    <a class="dropdown-item" href=/<?php echo $modul?>/divisionPrint/?id=<?php echo $row["id"]?>>деление - печать на складе</a>
+                    <a class="dropdown-item" href=/<?php echo $modul?>/divisionPrintEdit/?id=<?php echo $row["id"]?>>деление - по цветам</a>
+                </div>
+            </div>
+
+            <a href="/shipment/edit/?id=<?php echo $row["id"]?>" class="btn btn-warning btn-sm me-2"><?php echo $store_orders_statuses[$row["status"]]?></a>
+            <small>дата продаж: <?php echo $row["date_start"]?>, создано <?php echo $row["date_add"]?>  <i><?php echo $row["comments"]?></i></small>
+
+
+
+
+        </div>
+
+        <div class="expanel-body" id="external__<?php echo $row["id"] ?>" style="display:none;">
+            <div class="row">
+                <?php
+                if (array_key_exists($row["id"], $dozakupka)) {
+                    foreach($dozakupka[$row["id"]] as $rows) {
+
+                    ?>
+                        <div class="col-12">
+                            <div class="ml-4">
+                                <a href=/<?php echo $modul?>/fields-data/?id=<?php echo $rows["id"]?> class="btn btn-white fs-6 me-3">
+                                    <span class="btn btn-outline-info fs-6 me-2"><?php echo $rows["id"]?></span><?php echo $rows["name"]?>
+                                    <span class="me-2 btn btn-sm bg-warning"><?php echo $store_orders_statuses[$rows["status"]]?></span>
+                                </a>
+                                <div class="dropdown d-inline-block">
+                                    <button type="button" class="btn bg-dark-transparent dropdown-toggle"  onclick="$(this).parent().children('.dropdown-menu').toggle();">действия </button>
+                                    <div class="dropdown-menu" style="">
+                                        <a class="dropdown-item" href="/shipment/add/?id=<?php echo $rows["id"]?>">правка</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/view/?id=<?php echo $rows["id"]?>>старый интерфейс</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/view2/?id=<?php echo $rows["id"]?>>новый интерфейс</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/fields-data/?id=<?php echo $rows["id"]?> >новый интерфейс2</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/division/?id=<?php echo $rows["id"]?>>деление</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/purchase/?id=<?php echo $rows["id"]?>>цвета для кустовых при заказе</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/divisionPrint/?id=<?php echo $rows["id"]?>>деление - печать на складе</a>
+                                        <a class="dropdown-item" href=/<?php echo $modul?>/divisionPrintEdit/?id=<?php echo $rows["id"]?>>деление - по цветам</a>
+                                    </div>
+                                </div>
+                                <i><?php echo $rows["comment"] ?? ''?></i>
+                                <table class="table"><tbody></tbody></table>
+                            </div>
+                        </div>
+                        <?php
+                    }
+                }
+                ?>
+
+            </div>
+        </div>
+
+
+    </div>
+
+
+
+
+
+<?php
+}
diff --git a/erp24/views/shipment/set-division-priority.php b/erp24/views/shipment/set-division-priority.php
new file mode 100644 (file)
index 0000000..c2e3061
--- /dev/null
@@ -0,0 +1,67 @@
+<?php
+
+use yii\widgets\ActiveForm;
+use yii\base\DynamicModel;
+
+use yii_app\helpers\PrintBlockHelper;
+
+use kartik\select2\Select2;
+
+/** @var $products array */
+/** @var $filterModel DynamicModel */
+/** @var $orderStoreSort array */
+/** @var $storeNamesByGuid array */
+/** @var $storePlanogramByStoreGuid array */
+/** @var $salesQuantity array */
+
+$this->registerCssFile('/yii_app/css/customSortable.css');
+$this->registerJsFile('/yii_app/js/Sortable.js', ['position' => \yii\web\View::POS_END]);
+$this->registerJsFile('/yii_app/js/customSortable.js', ['position' => \yii\web\View::POS_END]);
+
+?>
+
+<div class="setDivisionPriority m-5">
+    <?php $filterForm = ActiveForm::begin(['id' => 'filter-form']); ?>
+        <?php PrintBlockHelper::printBlock('Товар', $filterForm->field($filterModel, 'productId')->widget(Select2::class, [
+            'data' => $products,
+            'language' => 'ru',
+            'options' => ['placeholder' => 'Товар...'],
+            'pluginOptions' => [
+                'allowClear' => true,
+            ],
+            'pluginEvents' => [
+                'change' => 'function() {
+                    $("#filter-form").get(0).submit();
+                }',
+            ]
+        ])->label(false)); ?>
+    <?php ActiveForm::end(); ?>
+    <?php if ($orderStoreSort && $storeNamesByGuid && $storePlanogramByStoreGuid): ?>
+        <div class="row">
+            <div class="col-1"></div>
+            <div class="col-2">Магазин</div>
+            <div class="col-2">Продажи</div>
+            <div class="col-2">Планограмма минимум</div>
+            <div class="col-2">Планограмма максимум</div>
+        </div>
+        <div class="draganddropTable" data-name="stores#<?= $filterModel->productId ?>">
+            <?php foreach ($orderStoreSort as $orderStore): ?>
+                <div class="row">
+                    <div class="col-1 drag-handler"></div>
+                    <div class="col-2">
+                        <?= $storeNamesByGuid[$orderStore->store_id] ?? '---' ?>
+                    </div>
+                    <div class="col-2">
+                        <?= $salesQuantity[$orderStore->store_id] ?? '---' ?>
+                    </div>
+                    <div class="col-2">
+                        <?= $storePlanogramByStoreGuid[$orderStore->store_id]->quantity ?? '---' ?>
+                    </div>
+                    <div class="col-2">
+                        <?= $storePlanogramByStoreGuid[$orderStore->store_id]->quantity_max ?? '---' ?>
+                    </div>
+                </div>
+            <?php endforeach; ?>
+        </div>
+    <?php endif; ?>
+</div>
index 65ee50b88f4d1ed6bfbdf1ff1faccc4688c1316a..1b08908425b4a2421f5f2e5e4e2b2a5cd649e0e5 100755 (executable)
@@ -11,6 +11,7 @@
 use yii\helpers\ArrayHelper;
 use yii\helpers\Html;
 use yii\widgets\ActiveForm;
+use yii\widgets\Pjax;
 use yii_app\forms\timetable\TabelSearchForm;
 use yii_app\helpers\HtmlHelper;
 use yii_app\records\AdminGroup;
@@ -145,6 +146,9 @@ for ($date = clone $startDatetime; $date <= $endDatetime; $date->modify('+1 day'
     $dates[] = clone $date;
 }
 ?>
+
+<?php Pjax::begin(['id' => 'some_pjax_id']) ?>
+
 <div class="table-responsive">
     <h3 class="text-center">График сотрудников <?= TabelSearchForm::stores()[$tabelForm->storeId] ?? '' ?> <?= HtmlHelper::getMonth($startDatetime) ?> <?= $startDatetime->format('Y') ?> г.</h3>
     <table class="timetable table table-bordered table-striped table-hover">
@@ -249,6 +253,9 @@ $rowNumber = 0;
 </table>
 <?php } ?>
 </div>
+
+<?php Pjax::end() ?>
+
 <div class="noprint">
 <?php foreach (\yii_app\records\Shift::all() as $shift) { ?>
     <br> <b><?= $shift->short_name; ?></b> - <?= $shift->name; ?>
@@ -298,22 +305,32 @@ $rowNumber = 0;
             });
         }
 
-        document.querySelectorAll('[data-plan-slot-cell]').forEach(function(element) {
-            element.addEventListener('click', function (event) {
-                event.stopPropagation();
-                let params = new URLSearchParams({
-                    adminId: element.dataset.userId,
-                    date: element.dataset.date,
-                    storeId: element.dataset.storeId
+        function planSlotCellActivate() {
+            document.querySelectorAll('[data-plan-slot-cell]').forEach(function (element) {
+                element.addEventListener('click', function (event) {
+                    event.stopPropagation();
+                    let params = new URLSearchParams({
+                        adminId: element.dataset.userId,
+                        date: element.dataset.date,
+                        storeId: element.dataset.storeId
+                    })
+                    fetch('/timetable/edit_plan/?' + params, {method: 'get'}).then(response => response.text()).then(function (text) {
+                        var intervalTime = setInterval(() => {
+                            if ($("#modal-7").css('display') == 'none') {
+                                clearInterval(intervalTime);
+                                setTimeout(() => planSlotCellActivate(), 2000);
+                                $.pjax.reload({container: '#some_pjax_id', async: false});
+                            }
+                        }, 1000);
+                        return showModal({
+                            title: 'Добавить сотрудника в смену',
+                            body: text,
+                        });
+                    }).then(initModal)
                 })
-                fetch('/timetable/edit_plan/?' + params, {method: 'get'}).then(response => response.text()).then(function (text) {
-                    return showModal({
-                        title: 'Добавить сотрудника в смену',
-                        body: text,
-                    });
-                }).then(initModal)
             })
-        })
+        }
+        planSlotCellActivate();
     })();
 
     (function() {
index e5247e0b7243630804612ac291006227f929e1a8..1d64232780c100676c2b58a441ce9f7657b3773c 100644 (file)
@@ -43,7 +43,7 @@ if ($userModel->adminGroup->isRoaming()) {
     if (!empty($lastCheckin)) {\r
         if ($lastCheckin->isStart()) {\r
             $textButton = 'Закрытие смены';\r
-            $textInfo = 'Смена Ñ\83Ñ\81пеÑ\88но Ð·Ð°ÐºÑ\80Ñ\8bÑ\82иа';\r
+            $textInfo = 'Смена успешно закрыта';\r
             $flowersStyleClass = 'closure-flower';\r
             $lastCheckinTimeHours = date("d.m.Y H:i", strtotime($lastCheckin->time));\r
             $dateTimeHoursInfo = $lastCheckinTimeHours . ' - ' . date("H:i d.m.Y", strtotime($currentCheckin->time));\r
index 7c7e3cf9ac48092e9fddcc2ce605318d5c3a3ed3..fdc38e2612858500b6c5791b57dd2350a9f41263 100755 (executable)
@@ -7,6 +7,7 @@
 
 use yii\helpers\ArrayHelper;
 use yii_app\records\AdminGroup;
+use yii_app\records\Timetable;
 
 ?>
 <?php if ($success) { ?>
@@ -19,7 +20,8 @@ use yii_app\records\AdminGroup;
 <?= \yii\helpers\Html::activeHiddenInput($slot, 'tabel'); ?>
 <div class="row">
     <div class="col-lg-6">
-        <?= $form->field($slot, 'shift_id')->dropDownList(ArrayHelper::map(($slot->admin && $slot->admin->adminGroup) ? $slot->admin->adminGroup->shift: [], 'id', 'name')); ?>
+        <?= $form->field($slot, 'shift_id')->dropDownList(ArrayHelper::map(($slot->admin && $slot->admin->adminGroup) ? $slot->admin->adminGroup->shift: [], 'id', 'name'),
+            ['onchange' => '$("#timetableplan-time_start").val(this.value == 1 ? "08:00:00" : "20:00:00"); $("#timetableplan-time_end").val(this.value == 1 ? "20:00:00" : "08:00:00");']); ?>
     </div>
     <div class="col-lg-6">
     <?= $form->field($slot, 'store_id')->dropDownList(\yii_app\forms\timetable\TabelSearchForm::stores()); ?>
@@ -55,16 +57,44 @@ use yii_app\records\AdminGroup;
     </div>
 </div>
 
-<?= $form->field($slot, 'slot_type_id')->dropDownList($slot::slotTypeName()); ?>
+<?php
+
+$salariesDay = array_combine(
+        array_merge([0], Timetable::getSalariesDay()),
+        array_merge(['из окладов'], Timetable::getSalariesDay()),
+);
+if ($slot->d_id == \yii_app\records\Admin::PART_TIME_WORKER_GROUP_ID) {
+    ?>
+    <div class="row">
+        <div class="col-lg-6">
+            <?= $form->field($slot, 'slot_type_id')->dropDownList($slot::slotTypeName()); ?>
+        </div>
+        <div class="col-lg-6">
+            <?= $form->field($slot, 'salary_shift')->dropDownList($salariesDay); ?>
+        </div>
+    </div><?php
+} else {
+    echo $form->field($slot, 'slot_type_id')->dropDownList($slot::slotTypeName());
+}
+?>
+
 <?= $form->field($slot, 'comment'); ?>
 <?= $form->field($slot, 'status')->dropDownList($slot::statuses()); ?>
-<?= \yii\helpers\Html::submitButton('Сохранить', ['class' => 'btn btn-primary']); ?>
-<?php if ($slot->id) { ?>
-<?= \yii\helpers\Html::a('Удалить', \yii\helpers\Url::to(['/timetable/edit_plan?delete&id=' . $slot->id], ['data-role'=>'delete', 'class' => 'btn'])); ?>
-    <?php if (in_array($_SESSION['group_id'], [1, 8]) && !empty($fact)) { /** @TODO Add RBAC */ ?>
-        <br>
-        <hr>
+<?php
+$session = Yii::$app->session;
+$groupId = (int) $session->get('group_id');
+$numDay = Timetable::getCountDaysAllowEditShift($groupId);
+if (Timetable::getAllowEditShift($slot->date, $numDay)) {
+    ?>
+    <?= \yii\helpers\Html::submitButton('Сохранить.', ['class' => 'btn btn-primary']); ?>
+    <?php if ($slot->id) { ?>
+        <?= \yii\helpers\Html::a('Удалить', \yii\helpers\Url::to(['/timetable/edit_plan?delete&id=' . $slot->id], ['data-role'=>'delete', 'class' => 'btn'])); ?>
+        <?php if (in_array($_SESSION['group_id'], [1, 8]) && !empty($fact)) { /** @TODO Add RBAC */ ?>
+            <br>
+            <hr>
             <?= \yii\helpers\Html::a(' <div class="btn btn-danger">Удалить смену и факт </div>', \yii\helpers\Url::to(['/timetable/edit_plan?delete&force&id=' . $slot->id]), ['data-role'=>'delete', 'data-confirm' => 'Удалить?' , 'style' => "color:#fff!important;"]); ?>
+        <?php } ?>
     <?php } ?>
-<?php } ?>
+    <?php
+} ?>
 <?php $form::end() ?>