From 9c35f4e35e18265f0f370dc78d54866ed0bf9287 Mon Sep 17 00:00:00 2001 From: vasya Date: Fri, 27 Feb 2026 18:49:27 +0300 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D1=8E=20=D0=B2=D1=81=D0=B5=20=D0=B8=D0=B7=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82?= =?UTF-8?q?=D0=B0=20=D0=BD=D0=B0=20=D1=82=D0=B5=D0=BA=D1=83=D1=89=D0=B8?= =?UTF-8?q?=D0=B9=20=D0=BC=D0=BE=D0=BC=D0=B5=D0=BD=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 2 +- .env.example | 62 +- .gitignore | 25 +- .npmrc | Bin 0 -> 144 bytes .../App/Console/SendOrdersToTaxiCommand.php | 90 + Modules/Taxi/App/DTO/TaxiOrderDTO.php | 65 + Modules/Taxi/App/Http/Controllers/.gitkeep | 0 .../App/Http/Controllers/TaxiController.php | 350 + .../Middleware/CheckTimeRqstAvailability.php | 52 + .../App/Http/Requests/TaxiOrderRequest.php | 109 + Modules/Taxi/App/Jobs/TaxiMailJob.php | 40 + Modules/Taxi/App/Mail/BaseTaxiMail.php | 32 + Modules/Taxi/App/Mail/NewOrderMail.php | 39 + Modules/Taxi/App/Models/OfficeAddress.php | 13 + Modules/Taxi/App/Models/TaxiMain.php | 104 + Modules/Taxi/App/Models/TaxiTimePeriod.php | 14 + Modules/Taxi/App/Providers/.gitkeep | 0 .../App/Providers/RouteServiceProvider.php | 68 + .../Taxi/App/Providers/TaxiMailerProvider.php | 29 + .../Taxi/App/Providers/TaxiOrderProvider.php | 27 + .../App/Providers/TaxiScheduleProvider.php | 30 + .../App/Providers/TaxiServiceProvider.php | 114 + .../Taxi/App/Services/TaxiMailerService.php | 27 + .../Taxi/App/Services/TaxiOrderService.php | 42 + Modules/Taxi/Database/Seeders/.gitkeep | 0 .../Database/Seeders/TaxiDatabaseSeeder.php | 16 + .../2025_05_14_154131_create_main_table.php | 33 + .../2025_05_15_115637_create_hist_table.php | 34 + ...5_07_26_175151_create_taxi_time_period.php | 30 + ...5_07_28_140129_rename_taxi_time_period.php | 24 + .../2025_07_30_100041_change_taxi_main.php | 26 + ..._07_31_084251_change_taxi_main_archive.php | 28 + ..._07_31_085420_change_taxi_main_archive.php | 27 + .../2025_09_16_163054_renameTaxiAddress.php | 39 + .../2025_09_17_162746_addTaxiAddressFrom.php | 28 + .../2025_09_17_163551_notNullTaxiTo.php | 28 + .../2025_09_17_163846_notNullTaxiTo2.php | 28 + .../2025_09_17_164136_addTimePartOfDay.php | 28 + ...025_09_18_085136_renameTimeMorningTime.php | 24 + ...5_09_19_093041_createTaxiOfficesAddres.php | 29 + Modules/Taxi/composer.json | 31 + Modules/Taxi/config/.gitkeep | 0 Modules/Taxi/config/config.php | 8 + Modules/Taxi/module.json | 14 + Modules/Taxi/package.json | 15 + Modules/Taxi/resources/assets/js/app.jsx | 6 + Modules/Taxi/resources/assets/sass/app.scss | 0 Modules/Taxi/resources/css/taxiHome.css | 44 + Modules/Taxi/resources/css/taxiOrder.css | 3 + .../Taxi/resources/js/components/TaxiHome.tsx | 387 + .../resources/js/components/TaxiOrder.tsx | 635 + .../Taxi/resources/js/page/taxiHomePage.tsx | 13 + .../Taxi/resources/js/page/taxiOrderPage.tsx | 37 + .../Taxi/resources/js/types/taxiOrderType.ts | 50 + Modules/Taxi/resources/views/.gitkeep | 0 Modules/Taxi/resources/views/index.blade.php | 7 + .../resources/views/layouts/master.blade.php | 31 + .../Taxi/resources/views/taxi_home.blade.php | 13 + .../Taxi/resources/views/taxi_order.blade.php | 13 + Modules/Taxi/routes/.gitkeep | 0 Modules/Taxi/routes/api.php | 50 + Modules/Taxi/routes/web.php | 44 + Modules/Taxi/vite.config.js | 26 + Modules/Test/App/Http/Controllers/.gitkeep | 0 .../App/Http/Controllers/TestController.php | 67 + Modules/Test/App/Providers/.gitkeep | 0 .../App/Providers/RouteServiceProvider.php | 59 + .../App/Providers/TestServiceProvider.php | 114 + Modules/Test/Database/Seeders/.gitkeep | 0 .../Database/Seeders/TestDatabaseSeeder.php | 16 + Modules/Test/composer.json | 31 + Modules/Test/config/.gitkeep | 0 Modules/Test/config/config.php | 5 + Modules/Test/module.json | 11 + Modules/Test/package.json | 15 + Modules/Test/resources/assets/js/app.js | 0 Modules/Test/resources/assets/sass/app.scss | 0 Modules/Test/resources/views/.gitkeep | 0 Modules/Test/resources/views/index.blade.php | 7 + .../resources/views/layouts/master.blade.php | 29 + Modules/Test/routes/.gitkeep | 0 Modules/Test/routes/api.php | 19 + Modules/Test/routes/web.php | 19 + Modules/Test/vite.config.js | 26 + README.md | 60 +- app/Console/Commands/BaseScheduleCommand.php | 48 + app/Console/Commands/testDataCommand.php | 34 + app/Console/Kernel.php | 38 + app/DTO/ApiResponseDto.php | 27 + app/Enums/LogBusinessEvents.php | 36 + app/Exceptions/Handler.php | 30 + app/Facades/RedisNotifications.php | 15 + app/Facades/UserContext.php | 18 + app/Http/Controllers/AccessListController.php | 36 + app/Http/Controllers/AppHistoryController.php | 103 + .../Controllers/AuthorizationController.php | 28 + app/Http/Controllers/Controller.php | 8 +- app/Http/Controllers/LoginController.php | 248 + app/Http/Controllers/MenuController.php | 133 + app/Http/Controllers/TestController.php | 53 + app/Http/Controllers/TestDataController.php | 19 + app/Http/Controllers/TestFormController.php | 25 + app/Http/Kernel.php | 83 + app/Http/Middleware/Authenticate.php | 18 + app/Http/Middleware/AuthenticateMagic.php | 75 + app/Http/Middleware/AuthenticateMagicApi.php | 61 + app/Http/Middleware/CheckUserAppAccess.php | 39 + app/Http/Middleware/CheckUserPermission.php | 66 + app/Http/Middleware/EncryptCookies.php | 17 + .../PreventRequestsDuringMaintenance.php | 17 + .../Middleware/RedirectIfAuthenticated.php | 30 + app/Http/Middleware/TrimStrings.php | 19 + app/Http/Middleware/TrustHosts.php | 20 + app/Http/Middleware/TrustProxies.php | 28 + app/Http/Middleware/ValidateSignature.php | 22 + app/Http/Middleware/VerifyCsrfToken.php | 19 + app/Job/BaseJob.php | 39 + app/Mail/BaseMailerObj.php | 51 + app/Mail/Mailer.php | 145 + app/Models/AccessModel.php | 17 + app/Models/AppRoles.php | 18 + app/Models/MagicApps.php | 19 + app/Models/OldMagicModels/CcEmp.php | 13 + app/Models/TestData.php | 13 + app/Models/TestFormModel.php | 13 + app/Models/User.php | 42 +- app/Models/UserFavApp.php | 17 + app/Providers/ApiResponderProvider.php | 27 + app/Providers/AppServiceProvider.php | 10 +- app/Providers/AuthServiceProvider.php | 29 + .../AuthorizationServiceProvider.php | 30 + app/Providers/BroadcastServiceProvider.php | 19 + app/Providers/EventServiceProvider.php | 38 + app/Providers/RedisNotificationProvider.php | 30 + app/Providers/RouteServiceProvider.php | 40 + app/Providers/UserServiceProvider.php | 30 + app/Services/ApiResponder.php | 51 + app/Services/AuthorizationService.php | 86 + app/Services/ModuleService.php | 40 + app/Services/RedisBaseService.php | 78 + app/Services/RedisNotificationService.php | 99 + app/Services/UserService.php | 198 + app/Traits/LogsActivity_custom.php | 148 + artisan | 49 +- bootstrap/app.php | 67 +- composer.json | 52 +- composer.lock | 3848 +- config/activitylog.php | 53 + config/app.php | 120 +- config/auth.php | 47 +- config/broadcasting.php | 71 + config/cache.php | 42 +- config/cors.php | 34 + config/database.php | 117 +- config/filesystems.php | 18 +- config/hashing.php | 54 + config/ldap.php | 81 + config/logging.php | 53 +- config/mail.php | 68 +- config/modules.php | 232 + config/queue.php | 62 +- config/sanctum.php | 85 + config/services.php | 18 +- config/session.php | 77 +- config/view.php | 36 + .../2014_10_12_000000_create_users_table.php | 32 + ...000_create_password_reset_tokens_table.php | 28 + ..._08_19_000000_create_failed_jobs_table.php | 32 + ...01_create_personal_access_tokens_table.php | 33 + .../2025_02_20_121102_create_test_data.php | 27 + ...2025_02_21_093148_new_fields_test_data.php | 28 + .../2025_02_26_125247_test_form_data.php | 30 + .../2025_03_18_143411_create_menu_apps.php | 31 + .../2025_03_20_163008_create_user_fav_app.php | 30 + ...06_19_123055_create_activity_log_table.php | 27 + ...add_event_column_to_activity_log_table.php | 22 + ...atch_uuid_column_to_activity_log_table.php | 22 + ...01_165809_del_causer_from_activity_log.php | 26 + .../2025_08_03_192706_change_users.php | 32 + ...25_08_03_195248_add_login_column_users.php | 28 + ..._182433_add_activity_log_causer_fields.php | 29 + ...11_14_084642_new_table_schedule_result.php | 35 + .../2025_11_14_134023_create_access_table.php | 34 + .../2025_11_14_135641_change_menu_apps.php | 31 + ...1_14_142642_add_columns_for_magic_apps.php | 44 + ...11_14_161732_change_magic_apps_columns.php | 35 + ...15_171033_update_app_role_add_priority.php | 28 + ...9_204759_edit_app_roles_add_role_title.php | 28 + ...0_190514_edit_magic_apps_add_app_title.php | 28 + ..._11_142521_add_custom_event_actvitylog.php | 28 + database/seeders/DatabaseSeeder.php | 15 +- lang/en/auth.php | 20 + lang/en/pagination.php | 19 + lang/en/passwords.php | 22 + lang/en/validation.php | 191 + lang/ru/validation.php | 191 + modules_statuses.json | 4 + package-lock.json | 3555 ++ package.json | 39 +- phpunit.xml | 11 +- public/.htaccess | 4 - public/UML/authenticate ver 0.2.drawio | 664 + public/UML/authenticate.drawio | 701 + public/css/app.css | 11968 ++++ public/index.php | 47 +- public/js/app.js | 48249 ++++++++++++++++ resources/css/app.css | 196 +- .../css/components/MagicPopupContainer.css | 8 + resources/css/components/entityHistory.css | 121 + resources/css/components/formValidErr.css | 15 + resources/css/components/magicPopup.css | 104 + resources/css/components/preloader.css | 173 + resources/css/general.css | 43 + resources/css/main_styles.css | 27 + resources/css/variables.css | 7 + resources/js/api.js | 80 + resources/js/app.tsx | 14 + resources/js/bootstrap.js | 30 + resources/js/components/MagicLogin.tsx | 34 + resources/js/components/MagicPopup.tsx | 108 + .../js/components/MagicPopupContainer.tsx | 45 + resources/js/components/MenuApp.tsx | 231 + .../entityHistory/EntityHistory.tsx | 120 + .../components/formValidErr/FormValidErr.tsx | 30 + resources/js/components/header/Header.tsx | 51 + .../js/components/preloader/Preloader.tsx | 39 + resources/js/contexts/HistoryContext.tsx | 97 + resources/js/contexts/PopupContext.tsx | 41 + resources/js/contexts/PreloaderContext.tsx | 40 + resources/js/hooks/popup/MagicPopupHook.tsx | 32 + .../js/hooks/preloader/MagicPreloaderHook.tsx | 26 + resources/js/magicLogin.tsx | 7 + resources/js/main_script.tsx | 15 + resources/js/providers/AppProvider.tsx | 21 + resources/js/services/getCsrfService.ts | 20 + resources/sass/_variables.scss | 7 + resources/sass/app.scss | 8 + resources/views/access_list.blade.php | 22 + resources/views/app.blade.php | 16 + resources/views/layouts/app_main.blade.php | 28 + resources/views/magic_login.blade.php | 16 + resources/views/mail/mailer_default.blade.php | 12 + resources/views/menu_start.blade.php | 17 + resources/views/roles.blade.php | 40 + resources/views/test_form.blade.php | 18 + resources/views/welcome.blade.php | 360 +- routes/api.php | 51 + routes/channels.php | 18 + routes/console.php | 11 + routes/web.php | 54 + storage/app/.gitignore | 1 - stubs/nwidart-stubs/assets/js/app.stub | 0 stubs/nwidart-stubs/assets/sass/app.stub | 0 stubs/nwidart-stubs/channel.stub | 24 + stubs/nwidart-stubs/command.stub | 56 + stubs/nwidart-stubs/component-class.stub | 25 + stubs/nwidart-stubs/component-view.stub | 3 + stubs/nwidart-stubs/composer.stub | 31 + stubs/nwidart-stubs/controller-api.stub | 62 + stubs/nwidart-stubs/controller-plain.stub | 9 + stubs/nwidart-stubs/controller.stub | 67 + stubs/nwidart-stubs/event.stub | 26 + stubs/nwidart-stubs/factory.stub | 22 + stubs/nwidart-stubs/feature-test.stub | 20 + stubs/nwidart-stubs/job-queued.stub | 30 + stubs/nwidart-stubs/job.stub | 27 + stubs/nwidart-stubs/json.stub | 11 + stubs/nwidart-stubs/listener-duck.stub | 25 + stubs/nwidart-stubs/listener-queued-duck.stub | 27 + stubs/nwidart-stubs/listener-queued.stub | 28 + stubs/nwidart-stubs/listener.stub | 26 + stubs/nwidart-stubs/mail.stub | 29 + stubs/nwidart-stubs/middleware.stub | 17 + stubs/nwidart-stubs/migration/add.stub | 28 + stubs/nwidart-stubs/migration/create.stub | 28 + stubs/nwidart-stubs/migration/delete.stub | 28 + stubs/nwidart-stubs/migration/drop.stub | 28 + stubs/nwidart-stubs/migration/plain.stub | 24 + stubs/nwidart-stubs/model.stub | 22 + stubs/nwidart-stubs/notification.stub | 48 + stubs/nwidart-stubs/observer.stub | 48 + stubs/nwidart-stubs/package.stub | 15 + stubs/nwidart-stubs/policy.plain.stub | 18 + stubs/nwidart-stubs/provider.stub | 24 + stubs/nwidart-stubs/request.stub | 26 + stubs/nwidart-stubs/resource-collection.stub | 16 + stubs/nwidart-stubs/resource.stub | 16 + stubs/nwidart-stubs/route-provider.stub | 59 + stubs/nwidart-stubs/routes/api.stub | 19 + stubs/nwidart-stubs/routes/web.stub | 19 + stubs/nwidart-stubs/rule.implicit.stub | 22 + stubs/nwidart-stubs/rule.stub | 17 + stubs/nwidart-stubs/scaffold/config.stub | 5 + stubs/nwidart-stubs/scaffold/provider.stub | 114 + stubs/nwidart-stubs/seeder.stub | 16 + stubs/nwidart-stubs/unit-test.stub | 20 + stubs/nwidart-stubs/views/index.stub | 7 + stubs/nwidart-stubs/views/master.stub | 29 + stubs/nwidart-stubs/vite.stub | 26 + tests/CreatesApplication.php | 21 + tests/TestCase.php | 2 +- vite-module-loader.js | 45 + vite.config.js | 37 +- 303 files changed, 79434 insertions(+), 2558 deletions(-) create mode 100644 .npmrc create mode 100644 Modules/Taxi/App/Console/SendOrdersToTaxiCommand.php create mode 100644 Modules/Taxi/App/DTO/TaxiOrderDTO.php create mode 100644 Modules/Taxi/App/Http/Controllers/.gitkeep create mode 100644 Modules/Taxi/App/Http/Controllers/TaxiController.php create mode 100644 Modules/Taxi/App/Http/Middleware/CheckTimeRqstAvailability.php create mode 100644 Modules/Taxi/App/Http/Requests/TaxiOrderRequest.php create mode 100644 Modules/Taxi/App/Jobs/TaxiMailJob.php create mode 100644 Modules/Taxi/App/Mail/BaseTaxiMail.php create mode 100644 Modules/Taxi/App/Mail/NewOrderMail.php create mode 100644 Modules/Taxi/App/Models/OfficeAddress.php create mode 100644 Modules/Taxi/App/Models/TaxiMain.php create mode 100644 Modules/Taxi/App/Models/TaxiTimePeriod.php create mode 100644 Modules/Taxi/App/Providers/.gitkeep create mode 100644 Modules/Taxi/App/Providers/RouteServiceProvider.php create mode 100644 Modules/Taxi/App/Providers/TaxiMailerProvider.php create mode 100644 Modules/Taxi/App/Providers/TaxiOrderProvider.php create mode 100644 Modules/Taxi/App/Providers/TaxiScheduleProvider.php create mode 100644 Modules/Taxi/App/Providers/TaxiServiceProvider.php create mode 100644 Modules/Taxi/App/Services/TaxiMailerService.php create mode 100644 Modules/Taxi/App/Services/TaxiOrderService.php create mode 100644 Modules/Taxi/Database/Seeders/.gitkeep create mode 100644 Modules/Taxi/Database/Seeders/TaxiDatabaseSeeder.php create mode 100644 Modules/Taxi/Database/migrations/2025_05_14_154131_create_main_table.php create mode 100644 Modules/Taxi/Database/migrations/2025_05_15_115637_create_hist_table.php create mode 100644 Modules/Taxi/Database/migrations/2025_07_26_175151_create_taxi_time_period.php create mode 100644 Modules/Taxi/Database/migrations/2025_07_28_140129_rename_taxi_time_period.php create mode 100644 Modules/Taxi/Database/migrations/2025_07_30_100041_change_taxi_main.php create mode 100644 Modules/Taxi/Database/migrations/2025_07_31_084251_change_taxi_main_archive.php create mode 100644 Modules/Taxi/Database/migrations/2025_07_31_085420_change_taxi_main_archive.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_16_163054_renameTaxiAddress.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_17_162746_addTaxiAddressFrom.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_17_163551_notNullTaxiTo.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_17_163846_notNullTaxiTo2.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_17_164136_addTimePartOfDay.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_18_085136_renameTimeMorningTime.php create mode 100644 Modules/Taxi/Database/migrations/2025_09_19_093041_createTaxiOfficesAddres.php create mode 100644 Modules/Taxi/composer.json create mode 100644 Modules/Taxi/config/.gitkeep create mode 100644 Modules/Taxi/config/config.php create mode 100644 Modules/Taxi/module.json create mode 100644 Modules/Taxi/package.json create mode 100644 Modules/Taxi/resources/assets/js/app.jsx create mode 100644 Modules/Taxi/resources/assets/sass/app.scss create mode 100644 Modules/Taxi/resources/css/taxiHome.css create mode 100644 Modules/Taxi/resources/css/taxiOrder.css create mode 100644 Modules/Taxi/resources/js/components/TaxiHome.tsx create mode 100644 Modules/Taxi/resources/js/components/TaxiOrder.tsx create mode 100644 Modules/Taxi/resources/js/page/taxiHomePage.tsx create mode 100644 Modules/Taxi/resources/js/page/taxiOrderPage.tsx create mode 100644 Modules/Taxi/resources/js/types/taxiOrderType.ts create mode 100644 Modules/Taxi/resources/views/.gitkeep create mode 100644 Modules/Taxi/resources/views/index.blade.php create mode 100644 Modules/Taxi/resources/views/layouts/master.blade.php create mode 100644 Modules/Taxi/resources/views/taxi_home.blade.php create mode 100644 Modules/Taxi/resources/views/taxi_order.blade.php create mode 100644 Modules/Taxi/routes/.gitkeep create mode 100644 Modules/Taxi/routes/api.php create mode 100644 Modules/Taxi/routes/web.php create mode 100644 Modules/Taxi/vite.config.js create mode 100644 Modules/Test/App/Http/Controllers/.gitkeep create mode 100644 Modules/Test/App/Http/Controllers/TestController.php create mode 100644 Modules/Test/App/Providers/.gitkeep create mode 100644 Modules/Test/App/Providers/RouteServiceProvider.php create mode 100644 Modules/Test/App/Providers/TestServiceProvider.php create mode 100644 Modules/Test/Database/Seeders/.gitkeep create mode 100644 Modules/Test/Database/Seeders/TestDatabaseSeeder.php create mode 100644 Modules/Test/composer.json create mode 100644 Modules/Test/config/.gitkeep create mode 100644 Modules/Test/config/config.php create mode 100644 Modules/Test/module.json create mode 100644 Modules/Test/package.json create mode 100644 Modules/Test/resources/assets/js/app.js create mode 100644 Modules/Test/resources/assets/sass/app.scss create mode 100644 Modules/Test/resources/views/.gitkeep create mode 100644 Modules/Test/resources/views/index.blade.php create mode 100644 Modules/Test/resources/views/layouts/master.blade.php create mode 100644 Modules/Test/routes/.gitkeep create mode 100644 Modules/Test/routes/api.php create mode 100644 Modules/Test/routes/web.php create mode 100644 Modules/Test/vite.config.js create mode 100644 app/Console/Commands/BaseScheduleCommand.php create mode 100644 app/Console/Commands/testDataCommand.php create mode 100644 app/Console/Kernel.php create mode 100644 app/DTO/ApiResponseDto.php create mode 100644 app/Enums/LogBusinessEvents.php create mode 100644 app/Exceptions/Handler.php create mode 100644 app/Facades/RedisNotifications.php create mode 100644 app/Facades/UserContext.php create mode 100644 app/Http/Controllers/AccessListController.php create mode 100644 app/Http/Controllers/AppHistoryController.php create mode 100644 app/Http/Controllers/AuthorizationController.php create mode 100644 app/Http/Controllers/LoginController.php create mode 100644 app/Http/Controllers/MenuController.php create mode 100644 app/Http/Controllers/TestController.php create mode 100644 app/Http/Controllers/TestDataController.php create mode 100644 app/Http/Controllers/TestFormController.php create mode 100644 app/Http/Kernel.php create mode 100644 app/Http/Middleware/Authenticate.php create mode 100644 app/Http/Middleware/AuthenticateMagic.php create mode 100644 app/Http/Middleware/AuthenticateMagicApi.php create mode 100644 app/Http/Middleware/CheckUserAppAccess.php create mode 100644 app/Http/Middleware/CheckUserPermission.php create mode 100644 app/Http/Middleware/EncryptCookies.php create mode 100644 app/Http/Middleware/PreventRequestsDuringMaintenance.php create mode 100644 app/Http/Middleware/RedirectIfAuthenticated.php create mode 100644 app/Http/Middleware/TrimStrings.php create mode 100644 app/Http/Middleware/TrustHosts.php create mode 100644 app/Http/Middleware/TrustProxies.php create mode 100644 app/Http/Middleware/ValidateSignature.php create mode 100644 app/Http/Middleware/VerifyCsrfToken.php create mode 100644 app/Job/BaseJob.php create mode 100644 app/Mail/BaseMailerObj.php create mode 100644 app/Mail/Mailer.php create mode 100644 app/Models/AccessModel.php create mode 100644 app/Models/AppRoles.php create mode 100644 app/Models/MagicApps.php create mode 100644 app/Models/OldMagicModels/CcEmp.php create mode 100644 app/Models/TestData.php create mode 100644 app/Models/TestFormModel.php create mode 100644 app/Models/UserFavApp.php create mode 100644 app/Providers/ApiResponderProvider.php create mode 100644 app/Providers/AuthServiceProvider.php create mode 100644 app/Providers/AuthorizationServiceProvider.php create mode 100644 app/Providers/BroadcastServiceProvider.php create mode 100644 app/Providers/EventServiceProvider.php create mode 100644 app/Providers/RedisNotificationProvider.php create mode 100644 app/Providers/RouteServiceProvider.php create mode 100644 app/Providers/UserServiceProvider.php create mode 100644 app/Services/ApiResponder.php create mode 100644 app/Services/AuthorizationService.php create mode 100644 app/Services/ModuleService.php create mode 100644 app/Services/RedisBaseService.php create mode 100644 app/Services/RedisNotificationService.php create mode 100644 app/Services/UserService.php create mode 100644 app/Traits/LogsActivity_custom.php create mode 100644 config/activitylog.php create mode 100644 config/broadcasting.php create mode 100644 config/cors.php create mode 100644 config/hashing.php create mode 100644 config/ldap.php create mode 100644 config/modules.php create mode 100644 config/sanctum.php create mode 100644 config/view.php create mode 100644 database/migrations/2014_10_12_000000_create_users_table.php create mode 100644 database/migrations/2014_10_12_100000_create_password_reset_tokens_table.php create mode 100644 database/migrations/2019_08_19_000000_create_failed_jobs_table.php create mode 100644 database/migrations/2019_12_14_000001_create_personal_access_tokens_table.php create mode 100644 database/migrations/2025_02_20_121102_create_test_data.php create mode 100644 database/migrations/2025_02_21_093148_new_fields_test_data.php create mode 100644 database/migrations/2025_02_26_125247_test_form_data.php create mode 100644 database/migrations/2025_03_18_143411_create_menu_apps.php create mode 100644 database/migrations/2025_03_20_163008_create_user_fav_app.php create mode 100644 database/migrations/2025_06_19_123055_create_activity_log_table.php create mode 100644 database/migrations/2025_06_19_123056_add_event_column_to_activity_log_table.php create mode 100644 database/migrations/2025_06_19_123057_add_batch_uuid_column_to_activity_log_table.php create mode 100644 database/migrations/2025_08_01_165809_del_causer_from_activity_log.php create mode 100644 database/migrations/2025_08_03_192706_change_users.php create mode 100644 database/migrations/2025_08_03_195248_add_login_column_users.php create mode 100644 database/migrations/2025_08_10_182433_add_activity_log_causer_fields.php create mode 100644 database/migrations/2025_11_14_084642_new_table_schedule_result.php create mode 100644 database/migrations/2025_11_14_134023_create_access_table.php create mode 100644 database/migrations/2025_11_14_135641_change_menu_apps.php create mode 100644 database/migrations/2025_11_14_142642_add_columns_for_magic_apps.php create mode 100644 database/migrations/2025_11_14_161732_change_magic_apps_columns.php create mode 100644 database/migrations/2025_11_15_171033_update_app_role_add_priority.php create mode 100644 database/migrations/2025_11_19_204759_edit_app_roles_add_role_title.php create mode 100644 database/migrations/2025_11_20_190514_edit_magic_apps_add_app_title.php create mode 100644 database/migrations/2026_01_11_142521_add_custom_event_actvitylog.php create mode 100644 lang/en/auth.php create mode 100644 lang/en/pagination.php create mode 100644 lang/en/passwords.php create mode 100644 lang/en/validation.php create mode 100644 lang/ru/validation.php create mode 100644 modules_statuses.json create mode 100644 package-lock.json create mode 100644 public/UML/authenticate ver 0.2.drawio create mode 100644 public/UML/authenticate.drawio create mode 100644 public/css/app.css create mode 100644 public/js/app.js create mode 100644 resources/css/components/MagicPopupContainer.css create mode 100644 resources/css/components/entityHistory.css create mode 100644 resources/css/components/formValidErr.css create mode 100644 resources/css/components/magicPopup.css create mode 100644 resources/css/components/preloader.css create mode 100644 resources/css/general.css create mode 100644 resources/css/main_styles.css create mode 100644 resources/css/variables.css create mode 100644 resources/js/api.js create mode 100644 resources/js/app.tsx create mode 100644 resources/js/components/MagicLogin.tsx create mode 100644 resources/js/components/MagicPopup.tsx create mode 100644 resources/js/components/MagicPopupContainer.tsx create mode 100644 resources/js/components/MenuApp.tsx create mode 100644 resources/js/components/entityHistory/EntityHistory.tsx create mode 100644 resources/js/components/formValidErr/FormValidErr.tsx create mode 100644 resources/js/components/header/Header.tsx create mode 100644 resources/js/components/preloader/Preloader.tsx create mode 100644 resources/js/contexts/HistoryContext.tsx create mode 100644 resources/js/contexts/PopupContext.tsx create mode 100644 resources/js/contexts/PreloaderContext.tsx create mode 100644 resources/js/hooks/popup/MagicPopupHook.tsx create mode 100644 resources/js/hooks/preloader/MagicPreloaderHook.tsx create mode 100644 resources/js/magicLogin.tsx create mode 100644 resources/js/main_script.tsx create mode 100644 resources/js/providers/AppProvider.tsx create mode 100644 resources/js/services/getCsrfService.ts create mode 100644 resources/sass/_variables.scss create mode 100644 resources/sass/app.scss create mode 100644 resources/views/access_list.blade.php create mode 100644 resources/views/app.blade.php create mode 100644 resources/views/layouts/app_main.blade.php create mode 100644 resources/views/magic_login.blade.php create mode 100644 resources/views/mail/mailer_default.blade.php create mode 100644 resources/views/menu_start.blade.php create mode 100644 resources/views/roles.blade.php create mode 100644 resources/views/test_form.blade.php create mode 100644 routes/api.php create mode 100644 routes/channels.php create mode 100644 stubs/nwidart-stubs/assets/js/app.stub create mode 100644 stubs/nwidart-stubs/assets/sass/app.stub create mode 100644 stubs/nwidart-stubs/channel.stub create mode 100644 stubs/nwidart-stubs/command.stub create mode 100644 stubs/nwidart-stubs/component-class.stub create mode 100644 stubs/nwidart-stubs/component-view.stub create mode 100644 stubs/nwidart-stubs/composer.stub create mode 100644 stubs/nwidart-stubs/controller-api.stub create mode 100644 stubs/nwidart-stubs/controller-plain.stub create mode 100644 stubs/nwidart-stubs/controller.stub create mode 100644 stubs/nwidart-stubs/event.stub create mode 100644 stubs/nwidart-stubs/factory.stub create mode 100644 stubs/nwidart-stubs/feature-test.stub create mode 100644 stubs/nwidart-stubs/job-queued.stub create mode 100644 stubs/nwidart-stubs/job.stub create mode 100644 stubs/nwidart-stubs/json.stub create mode 100644 stubs/nwidart-stubs/listener-duck.stub create mode 100644 stubs/nwidart-stubs/listener-queued-duck.stub create mode 100644 stubs/nwidart-stubs/listener-queued.stub create mode 100644 stubs/nwidart-stubs/listener.stub create mode 100644 stubs/nwidart-stubs/mail.stub create mode 100644 stubs/nwidart-stubs/middleware.stub create mode 100644 stubs/nwidart-stubs/migration/add.stub create mode 100644 stubs/nwidart-stubs/migration/create.stub create mode 100644 stubs/nwidart-stubs/migration/delete.stub create mode 100644 stubs/nwidart-stubs/migration/drop.stub create mode 100644 stubs/nwidart-stubs/migration/plain.stub create mode 100644 stubs/nwidart-stubs/model.stub create mode 100644 stubs/nwidart-stubs/notification.stub create mode 100644 stubs/nwidart-stubs/observer.stub create mode 100644 stubs/nwidart-stubs/package.stub create mode 100644 stubs/nwidart-stubs/policy.plain.stub create mode 100644 stubs/nwidart-stubs/provider.stub create mode 100644 stubs/nwidart-stubs/request.stub create mode 100644 stubs/nwidart-stubs/resource-collection.stub create mode 100644 stubs/nwidart-stubs/resource.stub create mode 100644 stubs/nwidart-stubs/route-provider.stub create mode 100644 stubs/nwidart-stubs/routes/api.stub create mode 100644 stubs/nwidart-stubs/routes/web.stub create mode 100644 stubs/nwidart-stubs/rule.implicit.stub create mode 100644 stubs/nwidart-stubs/rule.stub create mode 100644 stubs/nwidart-stubs/scaffold/config.stub create mode 100644 stubs/nwidart-stubs/scaffold/provider.stub create mode 100644 stubs/nwidart-stubs/seeder.stub create mode 100644 stubs/nwidart-stubs/unit-test.stub create mode 100644 stubs/nwidart-stubs/views/index.stub create mode 100644 stubs/nwidart-stubs/views/master.stub create mode 100644 stubs/nwidart-stubs/vite.stub create mode 100644 tests/CreatesApplication.php create mode 100644 vite-module-loader.js diff --git a/.editorconfig b/.editorconfig index a186cd2..8f0de65 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,5 +14,5 @@ trim_trailing_whitespace = false [*.{yml,yaml}] indent_size = 2 -[compose.yaml] +[docker-compose.yml] indent_size = 4 diff --git a/.env.example b/.env.example index c0660ea..ea0665b 100644 --- a/.env.example +++ b/.env.example @@ -4,55 +4,36 @@ APP_KEY= APP_DEBUG=true APP_URL=http://localhost -APP_LOCALE=en -APP_FALLBACK_LOCALE=en -APP_FAKER_LOCALE=en_US - -APP_MAINTENANCE_DRIVER=file -# APP_MAINTENANCE_STORE=database - -# PHP_CLI_SERVER_WORKERS=4 - -BCRYPT_ROUNDS=12 - LOG_CHANNEL=stack -LOG_STACK=single LOG_DEPRECATIONS_CHANNEL=null LOG_LEVEL=debug -DB_CONNECTION=sqlite -# DB_HOST=127.0.0.1 -# DB_PORT=3306 -# DB_DATABASE=laravel -# DB_USERNAME=root -# DB_PASSWORD= +DB_CONNECTION=mysql +DB_HOST=127.0.0.1 +DB_PORT=3306 +DB_DATABASE=laravel +DB_USERNAME=root +DB_PASSWORD= -SESSION_DRIVER=database -SESSION_LIFETIME=120 -SESSION_ENCRYPT=false -SESSION_PATH=/ -SESSION_DOMAIN=null - -BROADCAST_CONNECTION=log +BROADCAST_DRIVER=log +CACHE_DRIVER=file FILESYSTEM_DISK=local -QUEUE_CONNECTION=database - -CACHE_STORE=database -# CACHE_PREFIX= +QUEUE_CONNECTION=sync +SESSION_DRIVER=file +SESSION_LIFETIME=120 MEMCACHED_HOST=127.0.0.1 -REDIS_CLIENT=phpredis REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379 -MAIL_MAILER=log -MAIL_SCHEME=null -MAIL_HOST=127.0.0.1 -MAIL_PORT=2525 +MAIL_MAILER=smtp +MAIL_HOST=mailpit +MAIL_PORT=1025 MAIL_USERNAME=null MAIL_PASSWORD=null +MAIL_ENCRYPTION=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" @@ -62,4 +43,17 @@ AWS_DEFAULT_REGION=us-east-1 AWS_BUCKET= AWS_USE_PATH_STYLE_ENDPOINT=false +PUSHER_APP_ID= +PUSHER_APP_KEY= +PUSHER_APP_SECRET= +PUSHER_HOST= +PUSHER_PORT=443 +PUSHER_SCHEME=https +PUSHER_APP_CLUSTER=mt1 + VITE_APP_NAME="${APP_NAME}" +VITE_PUSHER_APP_KEY="${PUSHER_APP_KEY}" +VITE_PUSHER_HOST="${PUSHER_HOST}" +VITE_PUSHER_PORT="${PUSHER_PORT}" +VITE_PUSHER_SCHEME="${PUSHER_SCHEME}" +VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" diff --git a/.gitignore b/.gitignore index b71b1ea..7fe978f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,24 +1,19 @@ -*.log -.DS_Store -.env -.env.backup -.env.production -.phpactor.json -.phpunit.result.cache -/.fleet -/.idea -/.nova /.phpunit.cache -/.vscode -/.zed -/auth.json /node_modules /public/build /public/hot /public/storage /storage/*.key -/storage/pail /vendor +.env +.env.backup +.env.production +.phpunit.result.cache Homestead.json Homestead.yaml -Thumbs.db +auth.json +npm-debug.log +yarn-error.log +/.fleet +/.idea +/.vscode diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000000000000000000000000000000000..29b674005f967944e70dcd042b162f9c88580d1c GIT binary patch literal 144 zcmZvVOA3H65JTTu@G5pM2p&Q31S0-6we$mec{S}?vX}`kB=6HRvNPdX7&tkwMB3sv sxgh7c>6D6+6Ejj!KGQ~Yme%qm5i4?$#7t>%Y7NRp-P~k;7Y#KPAGux}djJ3c literal 0 HcmV?d00001 diff --git a/Modules/Taxi/App/Console/SendOrdersToTaxiCommand.php b/Modules/Taxi/App/Console/SendOrdersToTaxiCommand.php new file mode 100644 index 0000000..072024a --- /dev/null +++ b/Modules/Taxi/App/Console/SendOrdersToTaxiCommand.php @@ -0,0 +1,90 @@ +executeCommand(function () { + $todayOrders = TaxiMain::where('cancel_rqst', 0) + ->where('taxi_date', (new DateTime())->format('Y-m-d')) + ->get() + ->toArray(); + + if (!$todayOrders) { + Mail::send(new Mailer( + new BaseMailerObj( + + ) + )); + echo '
'; var_dump('da'); echo'
'; + } else { + echo '
'; var_dump('net'); echo'
'; + } + + throw new Error('Ошипка!'); + }, 'еще инва'); + + // try { + // throw new Error('Ошипка!'); + // } catch (\Throwable $th) { + // \Log::channel('schedule_err')->error($th->getFile() . ": " . $th->getMessage() . " Line: " . $th->getLine()); + // } + + //$this->info('Daily report generated at ' . now()); + + return 0; + } + + /** + * Get the console command arguments. + */ + protected function getArguments(): array + { + return [ + ['example', InputArgument::REQUIRED, 'An example argument.'], + ]; + } + + /** + * Get the console command options. + */ + protected function getOptions(): array + { + return [ + ['example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null], + ]; + } +} diff --git a/Modules/Taxi/App/DTO/TaxiOrderDTO.php b/Modules/Taxi/App/DTO/TaxiOrderDTO.php new file mode 100644 index 0000000..995f132 --- /dev/null +++ b/Modules/Taxi/App/DTO/TaxiOrderDTO.php @@ -0,0 +1,65 @@ +validated(); + + switch ($rqstMethod) { + case 'PATCH': + return new self( + id: $validated['id'], + //При обновлении запроса логин пользователя должен оставаться неизменным + emp_login: $rqst->emp_login, + emp_phone: $validated['emp_phone'], + taxi_date: $validated['taxi_date'], + taxi_time: $validated['taxi_time'], + taxi_address_from: $validated['taxi_address_from'], + taxi_address_to: $validated['taxi_address_to'], + cancel_rqst: $validated['cancel_rqst'] ?? null, + ); + break; + default: + return new self( + id: $validated['id'] ?? null, + emp_login: $validated['emp_login'], + emp_phone: $validated['emp_phone'], + taxi_date: $validated['taxi_date'], + taxi_time: $validated['taxi_time'], + taxi_address_from: $validated['taxi_address_from'], + taxi_address_to: $validated['taxi_address_to'], + cancel_rqst: $validated['cancel_rqst'] ?? null, + ); + break; + } + } +} diff --git a/Modules/Taxi/App/Http/Controllers/.gitkeep b/Modules/Taxi/App/Http/Controllers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/Taxi/App/Http/Controllers/TaxiController.php b/Modules/Taxi/App/Http/Controllers/TaxiController.php new file mode 100644 index 0000000..ed160a9 --- /dev/null +++ b/Modules/Taxi/App/Http/Controllers/TaxiController.php @@ -0,0 +1,350 @@ +first(); + + return $taxiOrder; + } + + + /** + * Получение адресов офисов для подстановки в запросы такси + * + * @return array + */ + public function getOfficeAddress() + { + $taxiAddress = TaxiModels\OfficeAddress::all(); + + return $taxiAddress; + } + + + /** + * Получение всех активных заказов + * + * @return array + */ + public function getActiveOrders() + { + $todaydate = new DateTime(); + $todaydate->setTime(00, 00, 00); + $todaydate = $todaydate->format('Y-m-d'); + $orders = TaxiModels\TaxiMain::where('taxi_date', '>=', $todaydate) + ->get(); + + return $orders; + } + + + /** + * Метод получения заказов по условиям фильтра + * + * @param Request $rqst запрос с параметрами поиска + * @return string + */ + public function getFilterOrders(Request $rqst) + { + $rqstCond = []; + foreach ($rqst->all() as $fieldName => $fieldVal) { + if (!$fieldVal) continue; + $rqstCond[] = [$fieldName, '=', $fieldVal]; + } + $filterRqst = TaxiModels\TaxiMain::where($rqstCond)->get(); + + return json_encode($filterRqst->toArray()); + } + + + //ГАВРИЛОВ используй транзакцию, а то создается запрос, не отправляется письмо и сообщение об ошибке + /** + * Show the form for creating a new resource. + */ + public function createTaxiOrder(TaxiOrderRequest $rqst) + { + $validateData = TaxiOrderDTO::setTaxiOrderDTO($rqst, $rqst->method()); + //Пытаемся найти уже существующий запрос на этот же логин и эту же дату. Если запрос найден, возвращаем ошибку. + $searchExistsOrder = TaxiModels\TaxiMain::where([ + ['emp_login', '=', $validateData->emp_login], + ['taxi_date', '=', $validateData->taxi_date] + ])->take(1)->get(); + if (count($searchExistsOrder)) { + return response()->json(['message' => "Ошибка! Заявка для сотрудника $validateData->emp_login на дату $validateData->taxi_date уже существует"], 400); + } + // $createRqstMsg; + try { + $newOrderId = (new TaxiModels\TaxiMain())->createOrder($validateData); + //$newOrderId = $this->orderService->createOrder($validateData); + $createRqstMsg = "Заявка успешно создана. Номер $newOrderId"; + #Гаврилов + //ПРОВЕРЬ, ЧТОБЫ ПИСЬМО НЕ ОТПРАВЛЯЛОСЬ, ЕСЛИ ВОЗНИКАЕТ ОШИБКА НА ЭТАПЕ СОЗДАНИЯ ЗАЯВКИ + //Один метод отправки письма для всех методов работы с заказом: создание, редактирование, отмена + $this->sendMailService->sendMail(new NewOrderMail($validateData, $newOrderId)); + // SendMailNewOrder::dispatch(json_decode(json_encode($validateData), true), $newOrderId)->onQueue('emails')->delay(10); + // Mail::send(new Mailer( + // [$validateData->emp_login], + // 'Создание заказа на такси', + // "Для вас создана заявка на заказ такси на дату {$validateData->taxi_date} и время {$validateData->taxi_time}. Номер заказа {$newOrderId}", + // #Гаврилов + // //ЗДЕСЬ НЕПОНЯТНО ОТКУДА ВЗЯТЬ ЗНАЧЕНИЕ. ОБРАТИТЬСЯ К ЛОКАЛЬНО МОДУЛЬНОМУ ENV? + // config('taxi.name_ru'), + // )); + return response()->json( ['message' => "Заявка успешно создана. Номер заявки $newOrderId"] ); + } catch (\Throwable $t) { + #Гаврилов + //ОТПРАВКА СООБЩЕНИЯ С ОШИБКОЙ. ЗАТЕСТИ и отправляй response + //ОШИБКИ $T->GETmESSAGE НУЖНО ЛОГИРОВАТЬ, НО ПОЛЬЗОВАТЕЛЯМ ВЫВОДИТЬ ПРОСТО СООБЩЕНИЕ оШИБКА, ИНАЧЕ ОНИ ВИДЯТ ТЕХН ЧЕСКИЙ ТЕКСТ + //СНАЧАЛА ПЕРЕХВАТЫЙ EXCEPTION, ПОТОМ УЖЕ THOWBLE. EXCEPTION ВЫВОДИ ПОЛЬЗОВАТЕЛЮ, THORWBLE ЛОГИРУЙ ОТДЕЛЬНО + echo '
'; var_dump($t->getMessage()); echo'
'; + echo '
'; var_dump($t->getTrace()); echo'
'; + $createRqstMsg = "Ошибка!" . $t->getMessage() . ". Заявка не создана"; + return response()->json(['message' => $createRqstMsg], 400); + } + + //ГАВРИЛОВ + //ДОБАВЬ ФОРМИРОВАНИЕ ОТВЕТА ЧЕРЕЗ ГЕНЕРАЦИЮ РЕСУРСА, а не через response() + } + + + #Гаврилов + //ИСПОЛЬЗУЙ TaxiOrderRequest ПРИ ОБРАБОТКЕ ЗАЯВОК НА ТАКСИ + + /** + * Метод отмены запроса + * + * @param integer $rqstId идентификатор запроса + * @return string + */ + public function cancelRqst(int $rqstId): string + { + #Гаврилов + //ПОПРОБУЙ ОТПРАВИТЬ ЗАПРОС К API ЕНДПОИНТУ (ОТМЕНА ЗАПРОСА НА ТАКСИ) ЧЕРЕЗ POSTMAN С ПЕРЕДАЧЕЙ ЗАГОЛОВКА АУТЕНТИФИКАЦИИ С SANCTUM ТОКЕНОМ. ДОЛЖЕН ПРОПУСТИТЬ, А БЕЗ ЗАГОЛОВКА НЕ ДОЛЖЕН + $rqstData = $this->getOrderById($rqstId); + try { + #Гаврилов + //ПЕРЕНЕСИ ЭТУ ПРОВЕРКУ В РОУТИНГ? FINDORFAIL С РЕДИРЕКТОМ И ОШИБКОЙ + if (!$rqstData) { + throw new \Exception("Запрос $rqstId не существует"); + } + if (!$this->checkRqstDate($rqstData->taxi_date)) { + throw new \Exception("Дата запроса $rqstId уже прошла"); + } + } catch (\Throwable $t) { + return response()->json([ + 'errorMsg' => "Ошибка: $t->getMessage(). Заявка не отменена", + ], 400); + } + + $rqstData['cancel_rqst'] = 1; + $rqstData->save(); + + $this->sendMailService->sendCancelOrderMail($validateData, $newOrderId); + + // Mail::send(new Mailer( + // [$rqstData->emp_login], + // 'Отмена заказа на такси', + // "Заказ номер $rqstId на дату $rqstData->taxi_date и время $rqstData->taxi_time отменен", + // $this->appName)); + + return redirect('/taxi/home')->with([ + 'notification' => "Запрос $rqstId отменен", + 'notification_err' => false + ]); + } + + + /** + * Проверяем находится ли дата запроса на такси в диапазоне сегодняшнего или завтрашнего дня. + * + * @param string $rqstDate дата запроса на такси + * @return boolean + */ + private function checkRqstDate($rqstDate): bool + { + $todaydate = new DateTime(); + $todaydate->setTime(00, 00, 00); + + return new DateTime($rqstDate) >= $todaydate; + } + + + /** + * Получаем временные промежутки + * + * @return array + */ + public function getTimePeriods() + { + $empAllData = TaxiModels\TaxiTimePeriod::select('time_period', 'is_morning_time') + ->where('archive', 0) + ->get(); + + return $empAllData; + } + + + /** + * Метод получает информацию по всем активным пользователям + * + * @return array + */ + public function getActiveUsersInfo() + { + $empAllData = OldMagicModels\CcEmp::whereIn('emp_area', ['Курск', 'Пенза']) + ->whereNotIn('emp_state', ['Уволен', 'Декрет', 'Перевод на позицию', 'Перевод в ГРАН']) + ->get(); + foreach ($empAllData as &$empData) { + $empData['full_name'] = $empData['emp_surname'] . " " . $empData['emp_name'] . " " . $empData['emp_surname']; + $empData['extension_number'] = $empData['emp_phone']; + $empData['emp_phone'] = $empData['emp_mob_phone']; + } + + return $empAllData; + } + + + /** + * Метод получает информацию по конкретному пользователю + * + * @return array + */ + public function getUserInfoByLogin(string $userLogin) + { + $empLoginData = OldMagicModels\CcEmp::where('emp_login', $userLogin) + ->get(); + + // dd($empLoginData); + $empLoginData[0]['full_name'] = $empLoginData[0]['emp_surname'] . " " . $empLoginData[0]['emp_name'] . " " . $empLoginData[0]['emp_surname']; + $empLoginData[0]['extension_number'] = $empLoginData[0]['emp_phone']; + $empLoginData[0]['emp_phone'] = $empLoginData[0]['emp_mob_phone']; + + return $empLoginData; + } + + + #Гаврилов + //НЕ ЗАБУДЬ УДАЛИТЬ + public function testRedisMethod() + { + RedisNotifications::module('taxi') + ->notifications(['текст1', 'tеуые2']) + ->types(['error', 'success']) + ->put(); + } + + + /** + * Обновление заявки на такси + * + * @param TaxiOrderRequest $rqst информация по измененному запросу + * @return response + */ + public function updateTaxiOrder(TaxiOrderRequest $rqst) + { + try { + DB::beginTransaction(); + #Гаврилов + //ЕЩЕ РАЗ, ЧТО ЗА LOCKFORUPDATE + $orderData = TaxiModels\TaxiMain::lockForUpdate()->find($rqst->id); + $oldOrderData = TaxiModels\TaxiMain::find($rqst->id); + + if (!$orderData) { + throw new Exception("Заказ номер " . $rqst->id . " не найден"); + //return response()->json(['message' => 'Заказ номер ' . $rqst->id . ' не найден'], 400); + } + $editOrderData = TaxiOrderDTO::setTaxiOrderDTO($rqst, $rqst->method()); + #Гаврилов + //НА ДОМАШНЕЙ СТРАНИЦЕ ПОКАЗЫВАТЬ ТОЛЬКО ТЕ ЗАПРОСЫ, ДАТА КОТОРЫХ СЕГОДНЯ ИЛИ ЗАВТРА + $dateInterval = (new DateTime())->diff(new DateTime($orderData->taxi_date)); + if ($dateInterval->format('%R') == '-' && $dateInterval->format('%a') >= 1) { + throw new Exception("Нельзя менять заявки, дата которых уже прошла"); + // return response()->json(['message' => 'Нельзя менять заявки, дата которых уже прошла'], 400); + } + foreach($editOrderData as $fieldName => $fieldVal) { + if (isset($orderData->$fieldName)) { + $orderData[$fieldName] = $fieldVal; + } + } + $orderDataDiff = $orderData->getDirty(); + if (empty($orderDataDiff)) { + throw new Exception("Вы не внесли никаких изменений"); + //return response()->json(['message' => 'Вы не внесли никаких изменений'], 400); + } + $orderData->save(); + $this->sendMailService->sendEditOrderMail($oldOrderData->toArray(), $orderDataDiff, $orderData['id']); + + DB::commit(); + + return response()->json(['message' => 'Заявка успешно изменена'], 200); + } catch (\Exception $e) { + DB::rollBack(); + + return response()->json(['message' => "Ошибка." . $e->getMessage() . ". Не удалось обновить заявку"], 400); + } + + + + //ГАВРИЛОВ. ДОБАВЬ БЛОКИРОВКУ В МОМЕНТ ПОЛУЧЕНИЯ ДАННЫХ ПО РЕДАКТИРУЕМОМУ ЗАПРОСУ И ДО МОМЕНТА ЕГО ОБНОВЛЕНИЯ. ЛИБО ЧЕРЕЗ УСТАНОВКУ УРОВНЯ ИЗОЛЯЦИИ + + //ГАВРИЛОВ. ДОБАВЬ В DTO НЕ ОБНУЛЕНИЕ НЕНУЖНЫХД ДАННЫХ, А ПРИНУДИТЕЬНАЯ ИХ УСТАНОВКА. НАПРИМЕР ПРИ ОБНОВЛЕНИИ ЗАПРОСА НА ТАКСИ, УСТАНАВЛИВАТЬ EMP_LOGIN = ПЕРЕДАННОМУ ЗНАЧЕНИЮ, ВЗЯТОМУ ИЗ СУЩЕСТВУЮЩЕГО ЗАПРОСА. + + //Обновляем текущую модель, добавляя туда измененные значения, затем проверяем есть ли измененные значения через getDirty() + + + + + + //ГАВРИЛОВ. убрать поле Запрос актуален? и при отмене заявки убирать ее из таблицы Активные заявки + + //гаврилов. СДЕЛАТЬ ВОЗМОЖНОСТЬ ВЫГРУЗИТЬ В ОТЧЕТНОСТЬ ВСЕ ИМЕЮЩИЕСЯ ЗАЯВКИ В CSV ФАЙЛ. + } +} diff --git a/Modules/Taxi/App/Http/Middleware/CheckTimeRqstAvailability.php b/Modules/Taxi/App/Http/Middleware/CheckTimeRqstAvailability.php new file mode 100644 index 0000000..acd5122 --- /dev/null +++ b/Modules/Taxi/App/Http/Middleware/CheckTimeRqstAvailability.php @@ -0,0 +1,52 @@ +setTimezone($timezone); + $timeMax = (new \DateTime())->setTimezone($timezone); + $timeMin = (new \DateTime())->setTimezone($timezone); + $timeMax->setTime($maxRqstTime, 00, 00); + $timeMin->setTime($minRqstTime, 00, 00); + + #Гаврилов + //ПОМЕНЯЙ + if (!($timeNow > $timeMin && $timeNow < $timeMax)) { + //if (!($timeNow > $timeMin && $timeNow > $timeMax)) { + $errMsg = "Работа с заявками на такси заблокирована с $maxRqstTime:00 по 0$minRqstTime:00"; + #Гаврилов + //ПОДУМАТЬ КАКОЙ КОД ЛУЧШЕ ВЕРНУТЬ + //Метод expectsJson позволяет определить вызывается ли api роут через ajax/fetch, либо web route. + if ($request->expectsJson()) { + return response()->json([ + 'errorMsg' => $errMsg + ], 400); + } else { + #Гаврилов + //ПРОВЕРЬ КОГДА РЕАЛИЗУЕШЬ ОПОВЕЩЕНИЯ + return redirect('/taxi/home')->with([ + 'notification' => $errMsg, + 'notification_err' => true + ]); + } + } else { + return $next($request); + } + } +} diff --git a/Modules/Taxi/App/Http/Requests/TaxiOrderRequest.php b/Modules/Taxi/App/Http/Requests/TaxiOrderRequest.php new file mode 100644 index 0000000..effc731 --- /dev/null +++ b/Modules/Taxi/App/Http/Requests/TaxiOrderRequest.php @@ -0,0 +1,109 @@ +'; var_dump($this->all()); echo''; + } + + + /** + * Get the validation rules that apply to the request. + */ + public function rules(): array + { + //Получаем список активных пользователей + $empActiveLogins = OldMagicModels\CcEmp::select('emp_login') + ->whereNotIn('emp_state', ['Уволен', 'Декрет']) + ->get() + ->toArray(); + //Правила валидации + $validationRules = [ + 'id' => [ + 'int' + ], + 'taxi_date' => [ + 'date_format:Y-m-d', + //Заказ можно создать только на сегодняшний или завтрашний день + Rule::in([ + (new DateTime())->format('Y-m-d'), + (new DateTime())->modify('+1 day')->format('Y-m-d') + ]), + ], + 'taxi_time' => [ + 'required', + 'string', + 'regex:/^[0-9]{2}:[0-9]{2}$/', //время в формате 00:00 + ], + 'cancel_rqst' => 'boolean', + 'emp_phone' => [ + 'required', + 'int', + 'regex:/^(7|8)?[0-9]{10}$/' + ], + 'emp_login' => [ + $validationRules['emp_login'] = [ + 'required', + 'string', + 'regex:/^[a-z\-]+[0-9]*$/', + //Логины ищем среди активных логинов на текущий момент + Rule::in( + array_map(fn($el) => $el['emp_login'], $empActiveLogins) + ) + ], + ], + 'taxi_address_from' => [ + 'required', + 'string', + 'max: 500' + ], + 'taxi_address_to' => [ + 'required', + 'string', + 'max: 500' + ] + ]; + + //Во время создания запроса поле ID не валидируется + if ($this->isMethod('POST')){ + $validationRules['id'] = [ + 'prohibited' + ]; + } + + return $validationRules; + } + + /** + * Determine if the user is authorized to make this request. + */ + public function authorize(): bool + { + return true; + } + + /** + * Переопределение сообщений об ошибках валидации + * + * @return array + */ + public function messages(): array + { + return [ + 'taxi_date.in' => 'Заявку на такси можно завести только на сегодняшний или завтрашний день' + ]; + } +} diff --git a/Modules/Taxi/App/Jobs/TaxiMailJob.php b/Modules/Taxi/App/Jobs/TaxiMailJob.php new file mode 100644 index 0000000..a91a9ca --- /dev/null +++ b/Modules/Taxi/App/Jobs/TaxiMailJob.php @@ -0,0 +1,40 @@ +jobData + )); + } +} diff --git a/Modules/Taxi/App/Mail/BaseTaxiMail.php b/Modules/Taxi/App/Mail/BaseTaxiMail.php new file mode 100644 index 0000000..d3a2c43 --- /dev/null +++ b/Modules/Taxi/App/Mail/BaseTaxiMail.php @@ -0,0 +1,32 @@ +orderData->emp_login], + "Создана заявка на такси", + "Для вас создана заявка на такси № {$this->orderId}: + ", + config('taxi.name_ru'), + ); + } +} diff --git a/Modules/Taxi/App/Models/OfficeAddress.php b/Modules/Taxi/App/Models/OfficeAddress.php new file mode 100644 index 0000000..eaa3e33 --- /dev/null +++ b/Modules/Taxi/App/Models/OfficeAddress.php @@ -0,0 +1,13 @@ + 'dgavrilov', + // ]; + + // public function getActivitylogOptions(): LogOptions + // { + // return LogOptions::defaults() + // ->logAll() + // ->logOnlyDirty() + // ->useLogName('Taxi') + // ->logExcept(['created_at', 'updated_at']); + + // } + + public function __construct() + { + parent::__construct(); + //В трейте LogsActivity_custom это свойство отвечает за название приложения, события в котором логируются. Оно записывается в поле activity_log.log_name + $this->logActivity_custom__name = 'Taxi'; + $this->addCustomLogProperties(['custom__test' => 'test']); + } + + //ГАВРИЛОВ. сделай метод не статическим + public static function getFieldsTitle() + { + return [ + 'id' => 'Номер запроса', + 'emp_login' => 'Логин сотрудника', + 'emp_phone' => 'Телефон сотрудника', + 'taxi_date' => 'Дата заказа', + 'taxi_time' => 'Время заказа', + 'taxi_address_from' => 'Адрес откуда', + 'taxi_address_to' => 'Адрес куда', + 'cancel_rqst' => 'Запрос отменен', + ]; + + } + + public function createOrder(TaxiOrderDTO $orderData): string + { + //ГАВРИЛОВ. проверь будет ли возвращаться ошибка без try catch + // try { + + $this->logBusinessEvent(LogBusinessEvents::Create); + $newOrder = $this->create( + [ + 'emp_login' => $orderData->emp_login, + 'taxi_date' => $orderData->taxi_date, + 'emp_phone' => $orderData->emp_phone, + 'taxi_time' => $orderData->taxi_time, + 'taxi_address_from' => $orderData->taxi_address_from, + 'taxi_address_to' => $orderData->taxi_address_to + ] + ); + return $newOrder->id; + // } catch (\Exception $e) { + // return $e->getMessage(); + // } + } + + // /** + // * @return string Метод нужен для переопределения параметра трейта. Простое переопределение вызывает конфликт + // */ + //protected $logActivity_custom__name = 'Taxi'; + // public function getLogName(): string + // { + // return 'Taxi'; + // } + + //protected $logActivity_custom__name; + + // public function getActivitylogOptions(): LogOptions + // { + // //Через метод default() получаем параметры класса логирования по умолчанию. Ниже можем их переопределять в зависимости от специфики работы с моделью + // $logOptions = LogOptions::defaults() + // ->logOnly(['*']); //Устанавиваем список логируемых данных (полей модели), либо, как в этом случае, логируем все поля + // //->logExcept(['created_at', 'updated_at']) //Не логируем поля изменения и создания записи в ЛЮБОМ случае + // //->logOnlyDirty(); //Логируем только те поля, которые были изменены + // $logOptions->logName = 'Taxi'; //Устанавливаем значение для имени приложения + + // return $logOptions; + // } +} diff --git a/Modules/Taxi/App/Models/TaxiTimePeriod.php b/Modules/Taxi/App/Models/TaxiTimePeriod.php new file mode 100644 index 0000000..f0da70f --- /dev/null +++ b/Modules/Taxi/App/Models/TaxiTimePeriod.php @@ -0,0 +1,14 @@ +mapApiRoutes(); + + $this->mapWebRoutes(); + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + */ + protected function mapWebRoutes(): void + { + Route::middleware('web') + ->namespace($this->moduleNamespace) + ->group(module_path('Taxi', '/routes/web.php')); + + Route::prefix('taxi') + ->middleware('web') + ->group(base_path('Modules/Taxi/routes/web.php')); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + */ + protected function mapApiRoutes(): void + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->moduleNamespace) + ->group(module_path('Taxi', '/routes/api.php')); + + Route::prefix('taxi') + ->middleware('api') + ->group(base_path('Modules/Taxi/routes/api.php')); + } +} diff --git a/Modules/Taxi/App/Providers/TaxiMailerProvider.php b/Modules/Taxi/App/Providers/TaxiMailerProvider.php new file mode 100644 index 0000000..df122f4 --- /dev/null +++ b/Modules/Taxi/App/Providers/TaxiMailerProvider.php @@ -0,0 +1,29 @@ +app->bind(TaxiMailerService::class, function($app) { + return new TaxiMailerService(); + }); + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } +} diff --git a/Modules/Taxi/App/Providers/TaxiOrderProvider.php b/Modules/Taxi/App/Providers/TaxiOrderProvider.php new file mode 100644 index 0000000..11279e6 --- /dev/null +++ b/Modules/Taxi/App/Providers/TaxiOrderProvider.php @@ -0,0 +1,27 @@ +app->bind(TaxiOrderService::class, function($app) { + return new TaxiOrderService(); + }); + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } +} diff --git a/Modules/Taxi/App/Providers/TaxiScheduleProvider.php b/Modules/Taxi/App/Providers/TaxiScheduleProvider.php new file mode 100644 index 0000000..100fcc1 --- /dev/null +++ b/Modules/Taxi/App/Providers/TaxiScheduleProvider.php @@ -0,0 +1,30 @@ +app->runningInConsole()) { + $this->commands([ + SendOrdersToTaxiCommand::class, // ✅ Теперь Laravel знает о команде + ]); + } + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } +} diff --git a/Modules/Taxi/App/Providers/TaxiServiceProvider.php b/Modules/Taxi/App/Providers/TaxiServiceProvider.php new file mode 100644 index 0000000..c74c18e --- /dev/null +++ b/Modules/Taxi/App/Providers/TaxiServiceProvider.php @@ -0,0 +1,114 @@ +registerCommands(); + $this->registerCommandSchedules(); + $this->registerTranslations(); + $this->registerConfig(); + $this->registerViews(); + $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/migrations')); + } + + /** + * Register the service provider. + */ + public function register(): void + { + $this->app->register(RouteServiceProvider::class); + } + + /** + * Register commands in the format of Command::class + */ + protected function registerCommands(): void + { + // $this->commands([]); + } + + /** + * Register command Schedules. + */ + protected function registerCommandSchedules(): void + { + // $this->app->booted(function () { + // $schedule = $this->app->make(Schedule::class); + // $schedule->command('inspire')->hourly(); + // }); + } + + /** + * Register translations. + */ + public function registerTranslations(): void + { + $langPath = resource_path('lang/modules/'.$this->moduleNameLower); + + if (is_dir($langPath)) { + $this->loadTranslationsFrom($langPath, $this->moduleNameLower); + $this->loadJsonTranslationsFrom($langPath); + } else { + $this->loadTranslationsFrom(module_path($this->moduleName, 'lang'), $this->moduleNameLower); + $this->loadJsonTranslationsFrom(module_path($this->moduleName, 'lang')); + } + } + + /** + * Register config. + */ + protected function registerConfig(): void + { + $this->publishes([module_path($this->moduleName, 'config/config.php') => config_path($this->moduleNameLower.'.php')], 'config'); + $this->mergeConfigFrom(module_path($this->moduleName, 'config/config.php'), $this->moduleNameLower); + } + + /** + * Register views. + */ + public function registerViews(): void + { + $viewPath = resource_path('views/modules/'.$this->moduleNameLower); + $sourcePath = module_path($this->moduleName, 'resources/views'); + + $this->publishes([$sourcePath => $viewPath], ['views', $this->moduleNameLower.'-module-views']); + + $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower); + + $componentNamespace = str_replace('/', '\\', config('modules.namespace').'\\'.$this->moduleName.'\\'.config('modules.paths.generator.component-class.path')); + Blade::componentNamespace($componentNamespace, $this->moduleNameLower); + } + + /** + * Get the services provided by the provider. + */ + public function provides(): array + { + return []; + } + + private function getPublishableViewPaths(): array + { + $paths = []; + foreach (config('view.paths') as $path) { + if (is_dir($path.'/modules/'.$this->moduleNameLower)) { + $paths[] = $path.'/modules/'.$this->moduleNameLower; + } + } + + return $paths; + } +} diff --git a/Modules/Taxi/App/Services/TaxiMailerService.php b/Modules/Taxi/App/Services/TaxiMailerService.php new file mode 100644 index 0000000..0ad96f3 --- /dev/null +++ b/Modules/Taxi/App/Services/TaxiMailerService.php @@ -0,0 +1,27 @@ +prepareDataForMail())->onQueue('emails')->delay(5); + } +} diff --git a/Modules/Taxi/App/Services/TaxiOrderService.php b/Modules/Taxi/App/Services/TaxiOrderService.php new file mode 100644 index 0000000..4291c0a --- /dev/null +++ b/Modules/Taxi/App/Services/TaxiOrderService.php @@ -0,0 +1,42 @@ + $orderData->emp_login, + 'taxi_date' => $orderData->taxi_date, + 'emp_phone' => $orderData->emp_phone, + 'taxi_time' => $orderData->taxi_time, + 'taxi_address_from' => $orderData->taxi_address_from, + 'taxi_address_to' => $orderData->taxi_address_to + ] + ); + return $newOrder->id; + // } catch (\Exception $e) { + // return $e->getMessage(); + // } + } +} diff --git a/Modules/Taxi/Database/Seeders/.gitkeep b/Modules/Taxi/Database/Seeders/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/Taxi/Database/Seeders/TaxiDatabaseSeeder.php b/Modules/Taxi/Database/Seeders/TaxiDatabaseSeeder.php new file mode 100644 index 0000000..f9befc7 --- /dev/null +++ b/Modules/Taxi/Database/Seeders/TaxiDatabaseSeeder.php @@ -0,0 +1,16 @@ +call([]); + } +} diff --git a/Modules/Taxi/Database/migrations/2025_05_14_154131_create_main_table.php b/Modules/Taxi/Database/migrations/2025_05_14_154131_create_main_table.php new file mode 100644 index 0000000..273d6f2 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_05_14_154131_create_main_table.php @@ -0,0 +1,33 @@ +id(); + $table->string('emp_login', 30)->comment('логин сотрудника кто поедет'); + $table->string('emp_phone', 15)->comment('телефон сотрудника'); + $table->date('taxi_date')->comment('дата заказа такси'); + $table->time('taxi_time')->comment('время заказа такси'); + $table->string('taxi_address', 500)->comment('адрес заказа такси'); + $table->boolean('archive')->default(0); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('taxi_main'); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_05_15_115637_create_hist_table.php b/Modules/Taxi/Database/migrations/2025_05_15_115637_create_hist_table.php new file mode 100644 index 0000000..57d3a46 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_05_15_115637_create_hist_table.php @@ -0,0 +1,34 @@ +id('hist_id'); + $table->integer('id_change_row')->default(NULL)->comment('id изменяемой строки'); + $table->string('table_name', 50)->default(NULL)->comment('имя изменямой таблицы'); + $table->string('field_name', 50)->default(NULL)->comment('имя изменяемого поля'); + $table->string('emp_login', 50)->default(NULL)->comment('логин сотрудника, внесшего изменение'); + $table->string('value_before', 500)->default(NULL)->comment('значение ДО'); + $table->string('value_after', 500)->default(NULL)->comment('значение ПОСЛЕ'); + $table->timestamps(); + $table->comment('Таблица с историей изменений по процессу Заказ такси'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('taxi_hist'); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_07_26_175151_create_taxi_time_period.php b/Modules/Taxi/Database/migrations/2025_07_26_175151_create_taxi_time_period.php new file mode 100644 index 0000000..3a17e6c --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_07_26_175151_create_taxi_time_period.php @@ -0,0 +1,30 @@ +id(); + $table->string('time_period', 5)->comment('Временнoй промежуток'); + $table->boolean('archive')->default(0)->comment('Актуальность'); + $table->timestamps(); + $table->comment('Временные промежутки для заказа такси'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('taxi_time_period'); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_07_28_140129_rename_taxi_time_period.php b/Modules/Taxi/Database/migrations/2025_07_28_140129_rename_taxi_time_period.php new file mode 100644 index 0000000..f9240f6 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_07_28_140129_rename_taxi_time_period.php @@ -0,0 +1,24 @@ +string('taxi_time', 8)->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_07_31_084251_change_taxi_main_archive.php b/Modules/Taxi/Database/migrations/2025_07_31_084251_change_taxi_main_archive.php new file mode 100644 index 0000000..78f05e0 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_07_31_084251_change_taxi_main_archive.php @@ -0,0 +1,28 @@ +renameColumn('archive', 'cancel_rqst'); + $table->string('taxi_time', 6)->change(); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_07_31_085420_change_taxi_main_archive.php b/Modules/Taxi/Database/migrations/2025_07_31_085420_change_taxi_main_archive.php new file mode 100644 index 0000000..1a3ecf7 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_07_31_085420_change_taxi_main_archive.php @@ -0,0 +1,27 @@ +boolean('cancel_rqst')->default(0)->after('archive'); + $table->dropColumn('archive'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_16_163054_renameTaxiAddress.php b/Modules/Taxi/Database/migrations/2025_09_16_163054_renameTaxiAddress.php new file mode 100644 index 0000000..66a5d32 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_16_163054_renameTaxiAddress.php @@ -0,0 +1,39 @@ +renameColumn('taxi_address', 'order_addr_to'); + // }); + DB::statement('ALTER TABLE taxi_main CHANGE COLUMN taxi_address taxi_address_to Varchar(500)'); + // Schema::table('taxi_main', function (Blueprint $table) { + // $table->renameColumn('taxi_address', 'taxi_address_to')->change(); + // //$table->string('taxi_time', 8)->change(); + // }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + // Schema::table('taxi_main', function(Blueprint $table) { + // $table->renameColumn('order_addr_to', 'taxi_address'); + // }); + DB::statement('ALTER TABLE taxi_main CHANGE COLUMN taxi_address_to taxi_address Varchar(500)'); + // Schema::table('taxi_main', function (Blueprint $table) { + // //$table->renameColumn('archive', 'cancel_rqst'); + // $table->renameColumn('taxi_address_to', 'taxi_address')->change(); + // // $table->string('taxi_time', 6)->change(); + // }); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_17_162746_addTaxiAddressFrom.php b/Modules/Taxi/Database/migrations/2025_09_17_162746_addTaxiAddressFrom.php new file mode 100644 index 0000000..e87273b --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_17_162746_addTaxiAddressFrom.php @@ -0,0 +1,28 @@ +string('taxi_address_from', 500)->after('taxi_time')->comment('Адрес откуда ехать'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('taxi_main', function(Blueprint $table){ + $table->dropColumn('taxi_address_from'); + }); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_17_163551_notNullTaxiTo.php b/Modules/Taxi/Database/migrations/2025_09_17_163551_notNullTaxiTo.php new file mode 100644 index 0000000..adad32c --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_17_163551_notNullTaxiTo.php @@ -0,0 +1,28 @@ +string('taxi_address_from', 500)->nullable(false)->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('taxi_main', function(Blueprint $table){ + $table->string('taxi_address_from', 500)->nullable(true)->change(); + }); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_17_163846_notNullTaxiTo2.php b/Modules/Taxi/Database/migrations/2025_09_17_163846_notNullTaxiTo2.php new file mode 100644 index 0000000..6ee482b --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_17_163846_notNullTaxiTo2.php @@ -0,0 +1,28 @@ +string('taxi_address_to', 500)->nullable(false)->change(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('taxi_main', function(Blueprint $table){ + $table->string('taxi_address_to', 500)->nullable(true)->change(); + }); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_17_164136_addTimePartOfDay.php b/Modules/Taxi/Database/migrations/2025_09_17_164136_addTimePartOfDay.php new file mode 100644 index 0000000..5dd26bf --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_17_164136_addTimePartOfDay.php @@ -0,0 +1,28 @@ +boolean('morning_time')->after('time_period')->nullable(false)->default(true)->comment('Утренний промежуток времени'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('taxi_time_periods', function(Blueprint $table){ + $table->dropColumn('morning_time'); + }); + } +}; diff --git a/Modules/Taxi/Database/migrations/2025_09_18_085136_renameTimeMorningTime.php b/Modules/Taxi/Database/migrations/2025_09_18_085136_renameTimeMorningTime.php new file mode 100644 index 0000000..633ac48 --- /dev/null +++ b/Modules/Taxi/Database/migrations/2025_09_18_085136_renameTimeMorningTime.php @@ -0,0 +1,24 @@ +id(); + $table->string('place', 20)->nullable(false)->comment('Площадка'); + $table->string('address', 100)->nullable(false)->comment('Адрес'); + $table->comment('Адреса офисов для подстановки в заказы такси'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::drop('office_address'); + } +}; diff --git a/Modules/Taxi/composer.json b/Modules/Taxi/composer.json new file mode 100644 index 0000000..e0cdee0 --- /dev/null +++ b/Modules/Taxi/composer.json @@ -0,0 +1,31 @@ +{ + "name": "nwidart/taxi", + "description": "", + "authors": [ + { + "name": "Nicolas Widart", + "email": "n.widart@gmail.com" + } + ], + "extra": { + "laravel": { + "providers": [], + "aliases": { + + } + } + }, + "autoload": { + "psr-4": { + "Modules\\Taxi\\": "", + "Modules\\Taxi\\App\\": "app/", + "Modules\\Taxi\\Database\\Factories\\": "database/factories/", + "Modules\\Taxi\\Database\\Seeders\\": "database/seeders/" + } + }, + "autoload-dev": { + "psr-4": { + "Modules\\Taxi\\Tests\\": "tests/" + } + } +} diff --git a/Modules/Taxi/config/.gitkeep b/Modules/Taxi/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Modules/Taxi/config/config.php b/Modules/Taxi/config/config.php new file mode 100644 index 0000000..836ade5 --- /dev/null +++ b/Modules/Taxi/config/config.php @@ -0,0 +1,8 @@ + 'Taxi', + #Гаврилов + //КАК ЗАСТАВИТЬ ПРИ СОЗДАНИИ МОДУЛЯ ЭТОТ ПАРАМЕТР ПРОПИСЫВАТЬ АВТОМАТИЧЕСКИ? + 'name_ru' => 'Реестр заказа такси', //Добавляем вручную в каждый конфиг +]; diff --git a/Modules/Taxi/module.json b/Modules/Taxi/module.json new file mode 100644 index 0000000..acbf9ff --- /dev/null +++ b/Modules/Taxi/module.json @@ -0,0 +1,14 @@ +{ + "name": "Taxi", + "alias": "taxi", + "description": "", + "keywords": [], + "priority": 0, + "providers": [ + "Modules\\Taxi\\App\\Providers\\TaxiServiceProvider", + "Modules\\Taxi\\App\\Providers\\TaxiOrderProvider", + "Modules\\Taxi\\App\\Providers\\TaxiMailerProvider", + "Modules\\Taxi\\App\\Providers\\TaxiScheduleProvider" + ], + "files": [] +} diff --git a/Modules/Taxi/package.json b/Modules/Taxi/package.json new file mode 100644 index 0000000..d6fbfc8 --- /dev/null +++ b/Modules/Taxi/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build" + }, + "devDependencies": { + "axios": "^1.1.2", + "laravel-vite-plugin": "^0.7.5", + "sass": "^1.69.5", + "postcss": "^8.3.7", + "vite": "^4.0.0" + } +} diff --git a/Modules/Taxi/resources/assets/js/app.jsx b/Modules/Taxi/resources/assets/js/app.jsx new file mode 100644 index 0000000..9645277 --- /dev/null +++ b/Modules/Taxi/resources/assets/js/app.jsx @@ -0,0 +1,6 @@ +import { createRoot } from 'react-dom/client'; +import MenuApp from './components/MenuApp.jsx'; // Создайте этот файл, если используете React + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); diff --git a/Modules/Taxi/resources/assets/sass/app.scss b/Modules/Taxi/resources/assets/sass/app.scss new file mode 100644 index 0000000..e69de29 diff --git a/Modules/Taxi/resources/css/taxiHome.css b/Modules/Taxi/resources/css/taxiHome.css new file mode 100644 index 0000000..56b3ff5 --- /dev/null +++ b/Modules/Taxi/resources/css/taxiHome.css @@ -0,0 +1,44 @@ +table { + + & td { + padding: 5px; + } + & tr:nth-child(odd) { + background-color: #eeeeee; +} +} + +#taxi__order-create{ + padding: 10px; +} + +#taxi__home__filter-form{ + width: 20%; +} + +.taxi-btn{ + margin: 25px 0; +} + +.elem--title.el-title--big{ + padding: 7px; + margin: 50px 0 25px 0; + border-left: 5px solid #7864eb; + font-size: 1.3rem; + background: linear-gradient(90deg, rgb(237 234 255) 0%, rgb(255 255 255) 75%); + border-top-left-radius: 5px; + border-bottom-left-radius: 5px; + display: inline-block; + min-width: 400px; +} + +.form-field-block{ + display: flex; +} + +.taxi-orders__order-options{ + + & button { + margin: 10px 0; + } +} diff --git a/Modules/Taxi/resources/css/taxiOrder.css b/Modules/Taxi/resources/css/taxiOrder.css new file mode 100644 index 0000000..9f23b1d --- /dev/null +++ b/Modules/Taxi/resources/css/taxiOrder.css @@ -0,0 +1,3 @@ +.order-create__btn-block{ + margin: 20px 0; +} \ No newline at end of file diff --git a/Modules/Taxi/resources/js/components/TaxiHome.tsx b/Modules/Taxi/resources/js/components/TaxiHome.tsx new file mode 100644 index 0000000..62621eb --- /dev/null +++ b/Modules/Taxi/resources/js/components/TaxiHome.tsx @@ -0,0 +1,387 @@ +import { tr } from "date-fns/locale"; +import React, { useEffect, useState, useMemo, useContext } from "react"; +import { TaxiOrder_type, TaxiOrder_initial, TaxiOrder_fieldName, TaxiOrder_tableData } from '../types/taxiOrderType'; +import { differenceInDays } from 'date-fns'; +import { getCsrfToken } from "../../../../../resources/js/services/getCsrfService"; +import { Button, TextInput, Select, Option } from '@SharePoint/rencredit_uikit'; +import { EntityHistoryProps } from "../../../../../resources/js/components/entityHistory/EntityHistory"; +import { HistoryProvider, HistoryContext } from "../../../../../resources/js/contexts/HistoryContext"; +import { PopupContext } from "../../../../../resources/js/contexts/PopupContext"; +import { PreloaderContext } from "../../../../../resources/js/contexts/PreloaderContext"; +import api from "../../../../../resources/js/api"; + +type EmpSupervisorsData = { + emp_login: string, + emp_supervisor: string +} + +export default function TaxiHome () +{ + //Массив полей для отображения в таблицах с заяками. Учитывается, в том числе, порядок + const rqstTableFields = ['id', 'emp_login', 'emp_supervisor', 'emp_phone', 'taxi_date', 'taxi_time', 'taxi_address_from', 'taxi_address_to', 'cancel_rqst']; + //Формируем объект с полями для таблицы + const rqstTableHeaderFields: Record = Object.assign({}, ...rqstTableFields.map( field => {return {[field]: TaxiOrder_fieldName[field]}})); + const rqstTableHeader:string[] = Object.keys(TaxiOrder_fieldName).map(rqstFieldName => TaxiOrder_fieldName[rqstFieldName]); + const [ccEmp, setCcEmp] = useState([]); + //Стейт для руководителей сотрудников + const [empSupervisors, setEmpSupervisors] = useState([]); + const [allOrders, setAllOrders] = useState([]); + const [filterOrders, setFilterOrders] = useState([]); + const [startSearch, setStartSearch] = useState(false); + const [rqstNumber, setRqstNumber] = useState(''); + const [rqstTime, setRqstTime] = useState(''); + const [rqstLogin, setRqstLogin] = useState(''); + const [orderTimePeriods, setOrderTimePeriods] = useState<[{time_period: string}]>([{time_period: ''}]); + + const popupContext = useContext(PopupContext); + const preloaderContext = useContext(PreloaderContext); + + useEffect ( () => { + api.get('/taxi/getTimePeriods', + ).then(timePeriods_json => setOrderTimePeriods(timePeriods_json.data)); + + // fetch('/public/api/taxi/getTimePeriods', { + // method: 'GET', + // credentials: 'include', + // }).then(timePeriods_resp => timePeriods_resp.json().then( timePeriods_json => { + // setOrderTimePeriods(timePeriods_json); + // })); + + setTimeout(() => { + popupContext.addPopupArrTest([ + {message: 'для информации', timeOut: true, type: 'attention'} + ]) + popupContext.addPopupArrTest([ + {message: 'ошибка', timeOut: true, type: 'error'} + ]) + }, 1000); + console.log(Object.keys(TaxiOrder_fieldName)) + }, []) + + //ГАВРИЛОВ + //ЕСЛИ ОБЪЕКТ СО ЗНАЧЕНИЯМИ ДЛЯ ПОИСКА ПУСТОЙ - НЕ ВЫПОЛНЯЕМ ПОИСК, ВОЗВРАЩАЕМ ОПОВЕЩЕНИЕ О ПУСТЫХ УСЛОВИЯХ + const getFilterOrders = () => { + console.log(rqstTime) + console.log(rqstNumber) + console.log(rqstLogin) + setStartSearch(true); + // ГАВРИЛОВ. проверь + api.post('/taxi/getFilterOrders', { + id: rqstNumber, + taxi_time: rqstTime, + emp_login: rqstLogin + }).then(filterOrdersJson => { + setFilterOrders(filterOrdersJson.data); + }) + // fetch('/public/api/taxi/getFilterOrders', { + // credentials: 'include', + // method: 'POST', + // body: JSON.stringify({ + // id: rqstNumber, + // taxi_time: rqstTime, + // emp_login: rqstLogin + // }), + // headers: { + // 'content-type': 'application/json' + // } + // }).then(filterOrdersRqst => filterOrdersRqst.json()) + // .then(filterOrdersJson => { + // setFilterOrders(filterOrdersJson); + // }) + } + + const timePeriodOptions: Option[] = useMemo(() => { + return orderTimePeriods.map((time: {time_period: string}) => { + return { + caption: time.time_period, + value: time.time_period, + id: time.time_period + } + }) + }, [orderTimePeriods]) + + const empLoginOptions: Option[] = useMemo(() => { + return ccEmp.map((empLogin: string) => { + return { + caption: empLogin, + value: empLogin, + id: empLogin + } + }) + }, [ccEmp]) + + useEffect ( () => { + Promise.all( + [ + // fetch('/public/api/taxi/getEmpInfo', { + // credentials: 'include', + // method: 'GET', + // }).then( empInfo_resp => empInfo_resp.json() ), + api.get('taxi/getEmpInfo'), + api.get('taxi/getActiveOrders'), + // fetch('/public/api/taxi/getActiveOrders', { + // credentials: 'include', + // method: 'GET', + // }).then( allOrders_resp => allOrders_resp.json() ) + ] + ).then( + ([ + {data: empInfo_json}, + {data: allOrders_json} + ]) => { + setCcEmp(empInfo_json.map( (empInfoEl: {emp_login: String}) => empInfoEl.emp_login )); + setAllOrders(allOrders_json); + setEmpSupervisors(empInfo_json.map( (empInfoEl: {emp_login: String, emp_group: String}) => ({emp_login: empInfoEl.emp_login, emp_supervisor: empInfoEl.emp_group}) )); + } + ) + + }, []) + + const isReady = ccEmp.length > 0 && orderTimePeriods.length > 0; + + useEffect ( () => { + console.log(!isReady) + preloaderContext.setPreloaderVisible(!isReady) + // setPreloaderProp(!isReady); + // console.log(empSupervisors) + }, [isReady]) + + if (!ccEmp.length || !orderTimePeriods.length) { + //setIsReady(true); + return; + } else { + //setIsReady(false); + // console.log(allOrders); + console.log(ccEmp); + console.log(orderTimePeriods); + } + + // ГАВРИЛОВ. ОФОРМИ РЕЗУЛЬТАТЫ ПОИСКА. ПОСЛЕ ПОИСКА ПЛАВНО ОПУСКАЙ ДО ТАБЛИЦЫ РЕЗУЛЬТАТЫ ПОИСКА, ТАКЖЕ ВЫВЕДИ ЗОТЯ БЫ ТЕКСТ "РЕЗУЛЬТАТЫ ПОИСКА, СЕЙЧАС ЭТО ПРОСТО ТАБЛИЦА" + + //Гаврилов + //Реализовать подтягивание информации + //Реализовать переключение между БД (new and old Magic) + + //console.log(sanctumToken()) + + let newDate = new Date('2024-06-05'); + newDate.setHours(0, 0, 0); + + // function callHistory(entityId) { + // console.log(entityId) + + // return fakeObjArr; + // } + + + // let resultObj = { + // entityId: 1, + // entityProps: fakeObjArr + // } + + return ( +
+ */} + +
+
+ { + startSearch ? + + + + { + rqstTableHeader.map( (headEl, headElIndex) => + ) + } + + + + { + filterOrders.length ? + filterOrders.map( (rqstData: TaxiOrder_type, rqstIndex: number) => + + { + Object.keys(TaxiOrder_initial).map(initField => + ) + } + ) + : + + + } + +
+ {headEl} +
+ {initField == 'cancel_rqst' ? (rqstData[initField] ? 'Нет' : 'Да') : rqstData[initField]} +
Запросов не найдено
+ : '' + } +
+ + ) +} + + +function RqstTable(props: {allOrders: TaxiOrder_type[], rqstTableHeader: Record, empSupervisors: EmpSupervisorsData[]}){ + const historyContext = useContext(HistoryContext); + if (!historyContext) { + return null; + } + let newDate = new Date('2024-06-05'); + newDate.setHours(0, 0, 0); + return ( + props.allOrders.length ? + + + + { + Object.entries(props.rqstTableHeader).map((el, index) => + + ) + } + + + + + { + props.allOrders.map( (rqstData: TaxiOrder_type, rqstIndex: number) => + + { + Object.entries(props.rqstTableHeader).map( el => { + return ( + // Если поле - руководитель сотрудника - вычисляем значение, ориентируясь на список props.empSupervisors + el[0] === 'emp_supervisor' ? + + : + ) + }) + } + + + ) + } + +
{el[1]}Управление
{ props.empSupervisors.find(empData => empData.emp_login == rqstData.emp_login)?.emp_supervisor }{ rqstData[el[0]] } + {/* Можно взаимодействовать только с заявками на такси на сегодняшнюю, либо завтрашнюю дату */} + {differenceInDays(new Date(rqstData.taxi_date), new Date()) >= 0 && !rqstData.cancel_rqst ? + <> +
+ :
Нет активных заявок
+ ) +} diff --git a/Modules/Taxi/resources/js/components/TaxiOrder.tsx b/Modules/Taxi/resources/js/components/TaxiOrder.tsx new file mode 100644 index 0000000..aa0ac67 --- /dev/null +++ b/Modules/Taxi/resources/js/components/TaxiOrder.tsx @@ -0,0 +1,635 @@ +import React, { useEffect, useContext, useState, useMemo } from "react"; +import { TaxiOrder_type, TaxiOrder_initial } from '../types/taxiOrderType'; +import { addDays, format } from 'date-fns'; +import { getCsrfToken } from "../../../../../resources/js/services/getCsrfService"; +import { Button, TextInput, Select, Option } from '@SharePoint/rencredit_uikit'; +import FormValidErr, { FormValidErrObject } from "../../../../../resources/js/components/formValidErr/FormValidErr"; +import { PopupContext } from "../../../../../resources/js/contexts/PopupContext"; +import { EntityHistoryProps } from "../../../../../resources/js/components/entityHistory/EntityHistory"; +import { PreloaderContext } from "../../../../../resources/js/contexts/PreloaderContext"; + +//Гаврилов типы для пропсов? +// export default function TaxiOrder( {rqstId, setPreloaderProp}: {rqstId: number | undefined, setPreloaderProp: CallableFunction} ) +export default function TaxiOrder( {rqstId}: {rqstId: number | undefined} ) +{ + let newDate = new Date('2024-06-05'); + newDate.setHours(0, 0, 0); + let fakeObjArr: EntityHistoryProps[] = [ + { + changeAction: 'insert', + changeAuthor: 'login', + changeDate: newDate, + changeDetails: [ + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле2', + propValue: 'значение2' + } + ] + }, + { + changeAction: 'insert', + changeAuthor: 'login', + changeDate: new Date('2024-06-05'), + changeDetails: [ + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле2', + propValue: 'значение2' + } + ] + }, + { + changeAction: 'insert', + changeAuthor: 'login', + changeDate: new Date('2024-06-05'), + changeDetails: [ + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле', + propValue: 'значение' + }, + { + propName: 'поле2', + propValue: 'значение2' + } + ] + }, + { + changeAction: 'update', + changeAuthor: 'login2', + changeDate: new Date('2025-06-05'), + changeDetails: [ + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле5', + propValue: 'значение6' + } + ] + }, + { + changeAction: 'update', + changeAuthor: 'login2', + changeDate: new Date('2025-06-05'), + changeDetails: [ + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле3', + propValue: 'значение4' + }, + { + propName: 'поле5', + propValue: 'значение6' + } + ] + } + ]; + + const preloaderContext = useContext(PreloaderContext); + + //ГАВРИЛОВ ПОСТОЯННЫЙ ПЕРЕРЕНДЕРИНГ СПРОСИТЬ У САШИ. ЭЛЕМЕНТ НЕ МИГАЕТ В КОНСОЛИ, НО ПИШЕТ ПОСТОЯННО ПЕРЕРЕНДЕР + console.log('🔁 TaxiForm перерендерился!'); + interface UserData { + emp_id: number, + emp_address: string, + emp_lastname: string, + emp_name: string, + emp_surname: string, + emp_login: string | null + emp_phone: string, + //Все остальные поля объекта могут быть пустыми + [key: string]: unknown, + full_name: string, + }; + const UserData_initial: UserData = { + emp_id: 0, + emp_address: '', + emp_lastname: '', + emp_name: '', + emp_surname: '', + emp_login: '', + emp_phone: '', + full_name: '', + // _token: getCsrfToken() + }; + //Проверка загрузки необходимых для начала работ данных. После успешного получения всех данных происходит рендеринг + const [checkLoad, setCheckLoad] = useState( + { + ccEmp: false, + orderData: false, + checkEditOrderUserData: false, + getTimePeriods: false, + checkOfficeAddress: false, + } + ); + const todayDate = new Date(); + //Данные по всем пользователям + const [ccEmp, setCcEmp] = useState( [UserData_initial] ); + //Данные по редактируемому запросу (если вызвано редактирование) + const [orderData, setOrderData] = useState(TaxiOrder_initial); + //Данные по пользователю, чей запрос редактируется (если вызвано редактирование запроса) + const [editOrderUserData, setEditOrderUserData] = useState(UserData_initial); + //Данные по временным промежуткам + const [orderTimePeriods, setOrderTimePeriods] = useState< {time_period: string, is_morning_time: number}[] >( + [ {time_period: '', is_morning_time: 0} ] + ); + //Массив доступных для заказа такси дат для их дальнейшего преобразования в теги option селекта + const [dateOrderArr, setDateOrderArr] = useState( + [ + format(todayDate, "yyyy-MM-dd"), + format(addDays(todayDate, 1), "yyyy-MM-dd") + ] + ); + const popupContext = useContext(PopupContext); + useEffect ( () => { + setFormCreateVisible(true); + setFormCreateValidObj([{fieldName: 'testField', fieldErrors: ['errOne']}]); + console.log(popupContext) + // console.log() + // setTimeout(() => { + // popupContext.addPopupArrTest([ + // {message: 'для информации', timeOut: true, type: 'attention'} + // ]) + // }, 1000); + // setTimeout(() => { + // setPopupArrProp([ + // {message: 'для информации', timeOut: true, type: 'attention'}, + // ]) + // }, 1000); + // setTimeout(() => { + // setPopupArrProp([ + // {message: 'для информации', timeOut: false, type: 'info'}, + // ]) + // }, 2000); + // setTimeout(() => { + // setPopupArrProp([ + // {message: 'для информации', timeOut: false, type: 'info'}, + // ]) + // }, 3000); + // setPopupArrProp([ + // {message: 'для информации', timeOut: false, type: 'info'}, + // {message: 'успешно', timeOut: true, type: 'success'}, + // {message: 'ошибка', timeOut: true, type: 'error'}, + // {message: 'обратить внимание', timeOut: true, type: 'attention'} + // ]) + }, []) + + const [formCreateVisible, setFormCreateVisible] = useState(false); + const [formCreateValidErrObj, setFormCreateValidObj] = useState([{fieldName: null, fieldErrors: []}]) + + //ГАВРИЛОВ ДОБАВИТЬ ВСПЛЫВАЮЩЕЕ ОКНО ЕСЛИ ПРОИСХОДИТ НЕСООТВЕТСТВИЕ ВРЕМЕНИ И ДАТЫ ЗАКАЗА ТАКСИ? А НЕ ПРОСТО УДАЛЯТЬ ЗНАЧЕНИЕ ИЗ СОСЕДНЕГО ПОЛЯ? + + //Адреса офисов + const [officeAddressInfo, setOfficeAddressInfo] = useState< {place: string, address: string}[] >( + [ {place: '', address: ''} ] + ); + //Адрес офиса, где работает сотрудник. Определяется на этапе выбора логина + const [empOfficeAddress, setEmpOfficeAddress] = useState(null); + //const [orderTime, setOrderTime] = useState(null); + //const [orderDate, setOrderDate] = useState(null); + // const [orderAddressFrom, setOrderAddressFrom] = useState(null); + // const [orderAddressTo, setOrderAddressTo] = useState(null); + + function gotoHome() + { + document.location.href = '/public/taxi/home'; + } + + //Гаврилов. Не передаешь CSRF токен + //Отправка заказа на такси + function sendTaxiOrder () + { + console.log(orderData) + console.log(editOrderUserData) + //return + // setPreloaderProp(true, 'создаем заявку') + preloaderContext.setPreloaderVisible(true); + preloaderContext.setPreloaderText('создаем заявку'); + let popupType; + fetch('/public/api/taxi/' + (rqstId ? `editOrder/${rqstId}` : 'createRqst'), { + credentials: 'include', + method: (rqstId ? "PATCH" : "POST"), + body: JSON.stringify(orderData), + headers: { + 'content-type': 'application/json', + 'Accept': 'application/json' + } + }).then(result => { + preloaderContext.setPreloaderVisible(false); + // setPreloaderProp(false) + result.json().then(jsonResult => { + console.log(jsonResult) + if (!result.ok) { + //ГАВРИЛОВ здесь обработка ошибок валидации формы + if (result.status == 422) { + // setPopupArrProp( + // [ + // //ГАВРИЛОВ обработка ошибки + // {message: 'Произошла ошибка! Заявка не создана', type: 'error'}, + // ] + // ) + } else { + // setPopupArrProp( + // [ + // //ГАВРИЛОВ обработка ошибки + // {message: jsonResult.result_msg, type: 'error'}, + // ] + // ) + } + popupType = 'error' + } else { + popupType = 'success' + } + popupContext.addPopupArrTest( + [ + {message: jsonResult.message, type: popupType}, + ] + ) + }) + }) + } + +//Функция, собирающая нужный массив для формирования из него списка option для select +function transformToOptionsFunc ( + dataArr: T[], + dataKey?: keyof T +): Option[] { + let optionArr = dataArr.map(item => { + //Без проверки ниже, Typescript ругается на условный атрибут dataKey, который может отсутствовать, но при этом укаан как относящийся к Дженерику + const value = dataKey !== undefined + ? item[dataKey] + : item; + + return { + caption: String(value), + value: String(value), + id: String(value) + }; + }); + return optionArr; +} + + +/** + * Метод проверки соответствует ли дата и время заказа логике. Наприме, если дата заказа сегодняшняя - нельзя выбрать утренний промежуток времени + * @param orderTime время заказа такси + * @param orderDate дата заказа такси + * @returns результат проверки соответствия даты и времени заказа + */ +function checkTimeAndDate (orderTime: string|null, orderDate: string|null): boolean +{ + // console.log(orderTime) + // console.log(!orderTime) + // console.log(orderDate) + // console.log(!orderDate) + if (!orderTime || !orderDate) { + //console.log(1) + return true; + } + let isMorningTimeCheck = orderTimePeriods.filter( e => e.time_period == orderTime )[0].is_morning_time; + // console.log(isMorningTimeCheck) + //Если выбранная дата заказа больше текущей - заказ на завтра, можно выбирать любую дату + if (!(new Date(orderDate) > todayDate)) { + //console.log(2) + return !isMorningTimeCheck; + } + return true; +} + + // const ccEmpList: Option[] = useMemo(() => { + // return ccEmp.map(empData => { + // return { + // caption: empData.emp_login, + // value: empData.emp_login, + // id: empData.emp_login + // } + // }) + // }, [ccEmp]); + + // console.log(ccEmpList) + + + const ccEmpList = useMemo( () => { + return transformToOptionsFunc(ccEmp, 'emp_login'); + }, [ccEmp]); + + const orderDateList = useMemo( () => { + return transformToOptionsFunc(dateOrderArr); + }, [dateOrderArr]); + + const orderTimeList = useMemo( () => { + return transformToOptionsFunc(orderTimePeriods, 'time_period') + }, [orderTimePeriods]); + + //Загрузка данных для старта работ + useEffect ( () => { + //Получаем информацию по сотруднику при загрузке страницы + fetch('/public/api/taxi/getEmpInfo', { + credentials: 'include', + method: 'GET', + // headers: new Headers({ + // 'Authorization': `Bearer ${sanctumToken()}` + // }) + }).then(empInfo_resp => empInfo_resp.json().then(empInfo_json => { + console.log(empInfo_json) + console.log(editOrderUserData) + setCcEmp(empInfo_json); + setCheckLoad(loadObj => ( {...loadObj, ccEmp: true} )); + })); + //Получаем доступные временные промежутки для заказа такси + fetch('/public/api/taxi/getTimePeriods', { + method: 'GET', + credentials: 'include', + // headers: new Headers({ + // 'Authorization': `Bearer ${sanctumToken()}` + // }) + }).then(timePeriods_resp => timePeriods_resp.json().then(timePeriods_json => { + setOrderTimePeriods(timePeriods_json); + setCheckLoad(loadObj => ( {...loadObj, getTimePeriods: true} )); + })); + //ГАВРИЛОВ. ВЕЗДЕ В FETCH ЗАПРОСАХ ПЕРЕХВАТЫВАЙ ОШИБКИ И ВЫВОДИ СООБЩЕНИЯ ОБ ОШИБКЕ. НАПРИМЕМР С 401. В ЭТОМ СЛУЧАЕ НУЖНО ПЕРЕБРАСЫВАТЬ ПОЛЬЗОВАТЕЛЯ НА СТРАНИЦУ АУТЕНТИФИКАЦИИ + //Получае адреса всех офисов, куда могут заказываться такси? + fetch('/public/api/taxi/getOfficeAddress', { + method: 'GET', + credentials: 'include', + }).then(officeAddress_resp => {officeAddress_resp.json().then(officeAddress_json => { + setOfficeAddressInfo(officeAddress_json); + setCheckLoad(loadObj => ( {...loadObj, checkOfficeAddress: true} )); + })}); + //Если в пропсах передается rqstId, происходит редактирование заявки, а не создание новой - получаем данные по редактируемой заявке на такси + if (rqstId) { + fetch(`/public/api/taxi/getOrderById/${rqstId}`, { + method: 'GET', + credentials: 'include', + // headers: new Headers({ + // 'Authorization': `Bearer ${sanctumToken()}` + // }) + }).then(orderData_resp => orderData_resp.json().then( orderData_json => { + console.log(orderData_json) + setOrderData(orderData_json); + setCheckLoad(loadObj => ({...loadObj, orderData: true})); + })); + } + }, []) + + //гаврилов. Нужно ввести объект с данными по запросу и туда класть только нужные данные , а не все параметры пользователя. и тогда не нужно нигде проверять rqstId. Внизу в методе класть в этот объект все нужные параметры + + useEffect ( () => { + //Гаврилов. Причем тут проверка логина? Зачем она? + if (rqstId && orderData.emp_login) { + //Если передан id запроса на редактирование, устанавливаем значение с данными пользователя редактируемого запроса + fetch(`/public/api/taxi/getEmpInfo/${orderData.emp_login}`).then(userData_resp => userData_resp.json().then(userData_json => { + //гаврилов. Вот здесь нужно класть данные в orderData, а также заполнять адрес из и адрес куда + setEditOrderUserData(userData_json[0]); + //setOrderData(prevData => ({...prevData, userData_json[0]})); + //setEmpAddress(editOrderUserData['emp_address']); + setCheckLoad(loadObj => ( {...loadObj, checkEditOrderUserData: true} )); + //ГАВРИЛОВ. вынеси в отедльную функцию определение адреса офиса? + setEmpOfficeAddress(officeAddressInfo.filter(addressInfo => addressInfo.place == userData_json[0].emp_area)[0].address); + })); + } + }, [orderData.emp_login]) + + //Итоговая проверка все ли необходимые данные для рендеринга получены + const isReady = rqstId ? + checkLoad.ccEmp && checkLoad.checkEditOrderUserData && checkLoad.orderData && checkLoad.checkOfficeAddress && checkLoad.getTimePeriods + : checkLoad.ccEmp; + + //Регулировка видимости прелоадера в зависимости от того все ли данные для рендеринга получены или нет + useEffect ( () => { + //isReady ? setPreloaderProp(false) : setPreloaderProp(true); + isReady ? preloaderContext.setPreloaderVisible(false) : preloaderContext.setPreloaderVisible(true); + }, [isReady]) + + if (!isReady) { + return; + } + + return ( +
+ {/* */} +
+
+

{rqstId ? 'Редактирование' : 'Создание'} заявки на такси

+
+ {/* */} +
+ {/* ГАВРИЛОВ как защищаешься от csrf если комментируешь поле ниже? */} + {/* */} +
+ dateData.value === orderData.taxi_time) : null} + size = 'm' + onChange = {(_, sel:{caption:string, id:string, value:string}) => { + let selOrderTime = (sel ? sel.value : null); + setOrderData(prevData => ( {...prevData, taxi_time: selOrderTime} )); + //Проверяем относится ли выбранный промежуток времени заказа к утру или нет. Если выбран утренний промежуток, дата откуда - адрес сотрудника, адрес куда - офис, если выбран вечерний промежуток - наоборот + if (orderTimePeriods.filter( e => selOrderTime == e.time_period )[0].is_morning_time == 1) { + console.log(1) + setOrderData(prevData => ( {...prevData, taxi_address_from: editOrderUserData.emp_address, taxi_address_to: empOfficeAddress} )); + } else { + console.log(2) + console.log(empOfficeAddress) + setOrderData(prevData => ( {...prevData, taxi_address_from: empOfficeAddress, taxi_address_to: editOrderUserData.emp_address} )); + } + //Если проверка соответствия и времени заказа не выполняется, сбрасываем дату + if (!checkTimeAndDate(selOrderTime, orderData.taxi_date)) { + popupContext.addPopupArrTest( + [{message: 'Несоответствие времени и даты', type: 'error'}] + ) + setOrderData(prevData => ({...prevData, taxi_date: null})); + } + }} + /> +
+
+