diff --git a/app/Http/Controllers/Api/V1/SettingsController.php b/app/Http/Controllers/Api/V1/SettingsController.php index a4fed92..938a5f6 100644 --- a/app/Http/Controllers/Api/V1/SettingsController.php +++ b/app/Http/Controllers/Api/V1/SettingsController.php @@ -257,4 +257,77 @@ public function botSetting(Request $request, string $key): JsonResponse ], ]); } + + /** + * Get shift configuration + * + * GET /api/v1/settings/shift-config + */ + public function getShiftConfig(Request $request): JsonResponse + { + $dealershipId = $request->query('dealership_id') ? (int) $request->query('dealership_id') : null; + + $shiftConfig = [ + 'shift_1_start_time' => $this->settingsService->getShiftStartTime($dealershipId, 1), + 'shift_1_end_time' => $this->settingsService->getShiftEndTime($dealershipId, 1), + 'shift_2_start_time' => $this->settingsService->getShiftStartTime($dealershipId, 2), + 'shift_2_end_time' => $this->settingsService->getShiftEndTime($dealershipId, 2), + 'late_tolerance_minutes' => $this->settingsService->getLateTolerance($dealershipId), + ]; + + return response()->json([ + 'success' => true, + 'data' => $shiftConfig, + ]); + } + + /** + * Update shift configuration + * + * POST /api/v1/settings/shift-config + */ + public function updateShiftConfig(Request $request): JsonResponse + { + $validator = Validator::make($request->all(), [ + 'shift_1_start_time' => ['nullable', 'string', 'regex:/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/'], + 'shift_1_end_time' => ['nullable', 'string', 'regex:/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/'], + 'shift_2_start_time' => ['nullable', 'string', 'regex:/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/'], + 'shift_2_end_time' => ['nullable', 'string', 'regex:/^([0-1][0-9]|2[0-3]):[0-5][0-9]$/'], + 'late_tolerance_minutes' => ['nullable', 'integer', 'min:0', 'max:120'], + 'dealership_id' => ['nullable', 'integer'], + ]); + + if ($validator->fails()) { + return response()->json([ + 'success' => false, + 'errors' => $validator->errors(), + ], 422); + } + + try { + $data = $validator->validated(); + $dealershipId = $data['dealership_id'] ?? null; + unset($data['dealership_id']); + + $updatedSettings = []; + foreach ($data as $key => $value) { + if ($value !== null) { + $type = $key === 'late_tolerance_minutes' ? 'integer' : 'time'; + $this->settingsService->set($key, $value, $dealershipId, $type); + $updatedSettings[$key] = $value; + } + } + + return response()->json([ + 'success' => true, + 'message' => 'Shift configuration updated successfully', + 'data' => $updatedSettings, + ]); + } catch (\InvalidArgumentException $e) { + return response()->json([ + 'success' => false, + 'message' => $e->getMessage(), + ], 400); + } + } } \ No newline at end of file diff --git a/docs/FRONTEND_GUIDE.md b/docs/FRONTEND_GUIDE.md index c09787e..9d880e5 100644 --- a/docs/FRONTEND_GUIDE.md +++ b/docs/FRONTEND_GUIDE.md @@ -1531,19 +1531,12 @@ export interface Setting { updated_at: string; } -export interface BotConfig { - telegram_bot_id: string | null; - telegram_bot_username: string | null; - telegram_webhook_url: string | null; - notification_enabled: boolean; -} - export interface ShiftConfig { shift_1_start_time: string; shift_1_end_time: string; shift_2_start_time: string; shift_2_end_time: string; - allowed_late_minutes: number; + late_tolerance_minutes: number; } export const settingsApi = { @@ -1563,22 +1556,6 @@ export const settingsApi = { return response.data; }, - // Получить настройки бота - getBotConfig: async (dealership_id?: number): Promise => { - const response = await apiClient.get('/settings/bot-config', { - params: { dealership_id }, - }); - return response.data; - }, - - // Обновить настройки бота (только Manager/Owner) - updateBotConfig: async (data: Partial, dealership_id?: number): Promise => { - await apiClient.post('/settings/bot-config', { - ...data, - dealership_id, - }); - }, - // Получить настройки смен getShiftConfig: async (dealership_id?: number): Promise => { const response = await apiClient.get('/settings/shift-config', { diff --git a/docs/ROLE_HIERARCHY.md b/docs/ROLE_HIERARCHY.md index 122e5c4..7bc7dd3 100644 --- a/docs/ROLE_HIERARCHY.md +++ b/docs/ROLE_HIERARCHY.md @@ -143,10 +143,8 @@ public function updateSensitiveData(Request $request) ### Настройки (Settings) - `GET /api/v1/settings` - Все авторизованные пользователи - `GET /api/v1/settings/shift-config` - Все авторизованные пользователи -- `GET /api/v1/settings/bot-config` - Все авторизованные пользователи - `GET /api/v1/settings/{key}` - Все авторизованные пользователи - `POST /api/v1/settings/shift-config` - **Только Manager, Owner** -- `POST /api/v1/settings/bot-config` - **Только Manager, Owner** - `POST /api/v1/settings` - **Только Manager, Owner** - `PUT /api/v1/settings/{id}` - **Только Manager, Owner** - `DELETE /api/v1/settings/{id}` - **Только Manager, Owner** diff --git a/routes/api.php b/routes/api.php index 681658a..7e92aab 100644 --- a/routes/api.php +++ b/routes/api.php @@ -112,6 +112,9 @@ // Settings Route::get('/settings', [SettingsController::class, 'index']); + Route::get('/settings/shift-config', [SettingsController::class, 'getShiftConfig']); + Route::post('/settings/shift-config', [SettingsController::class, 'updateShiftConfig']) + ->middleware('role:manager,owner'); Route::get('/settings/{key}', [SettingsController::class, 'show']); Route::put('/settings/{key}', [SettingsController::class, 'update']) ->middleware('role:manager,owner'); diff --git a/swagger.yaml b/swagger.yaml index 07a5983..489a42b 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -3495,180 +3495,6 @@ paths: errors: type: object - /settings/bot-config: - get: - tags: - - Settings - summary: Получить конфигурацию бота - description: Получение настроек Telegram бота и смен - operationId: getBotConfig - security: - - bearerAuth: [] - parameters: - - name: dealership_id - in: query - description: ID автосалона (если не указан, возвращается глобальная конфигурация) - schema: - type: integer - example: 1 - responses: - '200': - description: Конфигурация бота - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - example: true - data: - type: object - properties: - telegram_bot_id: - type: string - nullable: true - example: "123456789:ABCdefGHIjklMNOpqrsTUVwxyz" - telegram_bot_username: - type: string - nullable: true - example: "taskmate_bot" - telegram_webhook_url: - type: string - format: uri - nullable: true - example: "https://example.com/api/webhook" - notification_enabled: - type: boolean - example: true - shift_1_start_time: - type: string - format: time - example: "09:00" - description: Время начала первой смены - shift_1_end_time: - type: string - format: time - example: "18:00" - description: Время окончания первой смены - shift_2_start_time: - type: string - format: time - example: "18:00" - description: Время начала второй смены - shift_2_end_time: - type: string - format: time - example: "02:00" - description: Время окончания второй смены - late_tolerance_minutes: - type: integer - example: 15 - description: Допустимое время опоздания в минутах - '401': - description: Неавторизован - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - - post: - tags: - - Settings - summary: Обновить конфигурацию бота - description: Обновление настроек Telegram бота и смен - operationId: updateBotConfig - security: - - bearerAuth: [] - requestBody: - required: true - content: - application/json: - schema: - type: object - properties: - telegram_bot_id: - type: string - nullable: true - description: Telegram Bot ID - example: "123456789:ABCdefGHIjklMNOpqrsTUVwxyz" - telegram_bot_username: - type: string - nullable: true - description: Telegram Bot Username - example: "taskmate_bot" - telegram_webhook_url: - type: string - format: uri - nullable: true - description: Telegram Webhook URL - example: "https://example.com/api/webhook" - notification_enabled: - type: boolean - nullable: true - description: Включить/выключить уведомления - example: true - shift_start_time: - type: string - format: time - nullable: true - description: Время начала смены (формат HH:MM) - example: "09:00" - shift_end_time: - type: string - format: time - nullable: true - description: Время окончания смены (формат HH:MM) - example: "18:00" - late_tolerance_minutes: - type: integer - nullable: true - description: Допустимое время опоздания в минутах - example: 15 - dealership_id: - type: integer - nullable: true - example: 1 - responses: - '200': - description: Конфигурация бота успешно обновлена - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - example: true - message: - type: string - example: Bot configuration updated successfully - data: - type: object - additionalProperties: - oneOf: - - type: string - - type: boolean - - type: integer - '401': - description: Неавторизован - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - '422': - description: Ошибка валидации - content: - application/json: - schema: - type: object - properties: - success: - type: boolean - example: false - errors: - type: object - /webhook: post: tags: