diff --git a/backend/api/v1/requests_app/serializers.py b/backend/api/v1/requests_app/serializers.py index 770a59d5..f9417337 100644 --- a/backend/api/v1/requests_app/serializers.py +++ b/backend/api/v1/requests_app/serializers.py @@ -245,8 +245,9 @@ class RequestWriteSerializer(serializers.ModelSerializer): def to_internal_value(self, data: Mapping[str, Any]) -> dict[str, Any]: """Предвалидационная очистка входа. - Для обычного пользователя удаляет `employee`, `status`, `approver` до полевой валидации, - чтобы не получить 400 из-за, например, несуществующего PK в `employee`. + Для обычного пользователя удаляет `employee`, `status`, `approver` + до полевой валидации, чтобы не получить 400 из-за, например, + несуществующего PK в `employee`. Args: data (Mapping[str, Any]): Входные данные запроса. @@ -260,6 +261,7 @@ class RequestWriteSerializer(serializers.ModelSerializer): data.pop("employee", None) data.pop("status", None) data.pop("approver", None) + return super().to_internal_value(data) def validate(self, attrs): @@ -316,7 +318,8 @@ class RequestWriteSerializer(serializers.ModelSerializer): def create(self, validated_data: dict[str, Any]) -> Request: """Создание заявки. - Обычным пользователям проставляет текущего пользователя; статус берётся из default модели. + Обычным пользователям проставляет текущего пользователя; + статус берётся из default модели. Args: validated_data (dict[str, Any]): Провалидированные данные. diff --git a/backend/static/js/components/recipientPicker.js b/backend/static/js/components/recipientPicker.js index 54011557..27299484 100644 --- a/backend/static/js/components/recipientPicker.js +++ b/backend/static/js/components/recipientPicker.js @@ -491,6 +491,9 @@ export class RecipientPicker { } triggerChange() { + // Очищаем ошибку при любом изменении + this.clearError(); + if (this.options.onChange) { this.options.onChange(this.getValues()); } @@ -505,6 +508,49 @@ export class RecipientPicker { }; } + /** + * Проверяет, заполнены ли получатели + * @returns {boolean} true если есть получатели или отделы + */ + validate() { + const hasDepartments = this.state.departments.length > 0; + const hasRecipients = this.state.recipients.length > 0; + const isValid = hasDepartments || hasRecipients; + + if (!isValid) { + this.setError('Укажите хотя бы одного получателя или отдел'); + } else { + this.clearError(); + } + + return isValid; + } + + /** + * Устанавливает сообщение об ошибке + * @param {string} message - Текст ошибки + */ + setError(message) { + this.clearError(); + const errorDiv = document.createElement('div'); + errorDiv.className = 'invalid-feedback d-block'; + errorDiv.textContent = message; + errorDiv.id = 'recipientPickerError'; + this.container.appendChild(errorDiv); + this.container.classList.add('is-invalid'); + } + + /** + * Убирает сообщение об ошибке + */ + clearError() { + const errorDiv = this.container.querySelector('#recipientPickerError'); + if (errorDiv) { + errorDiv.remove(); + } + this.container.classList.remove('is-invalid'); + } + setValues(data) { if (data.department_ids) { this.state.departments = Array.isArray(data.department_ids) diff --git a/backend/static/js/components/requestCrudHandler.js b/backend/static/js/components/requestCrudHandler.js index 1452ceb1..3f007c96 100644 --- a/backend/static/js/components/requestCrudHandler.js +++ b/backend/static/js/components/requestCrudHandler.js @@ -65,6 +65,23 @@ export function initRequestCrudHandler(options) { // Добавляем данные получателей из RecipientPicker if (createRecipientPicker) { + // Валидация: для обычной отправки должны быть получатели или отделы + if (saveAs === 'submit') { + if (!createRecipientPicker.validate()) { + return; + } + + // Проверка: автор не может быть получателем + const recipients = createRecipientPicker.getValues(); + if (recipients.recipient_ids && window.currentUserId) { + if (recipients.recipient_ids.includes(window.currentUserId)) { + alert('Вы не можете отправить заявление самому себе'); + createRecipientPicker.setError('Вы не можете быть получателем'); + return; + } + } + } + const recipients = createRecipientPicker.getValues(); // Добавляем department_ids @@ -146,6 +163,23 @@ export function initRequestCrudHandler(options) { // Добавляем данные получателей из RecipientPicker if (editRecipientPicker) { + // Валидация: для обычной отправки должны быть получатели или отделы + if (saveAs === 'submit') { + if (!editRecipientPicker.validate()) { + return; + } + + // Проверка: автор не может быть получателем + const recipients = editRecipientPicker.getValues(); + if (recipients.recipient_ids && window.currentUserId) { + if (recipients.recipient_ids.includes(window.currentUserId)) { + alert('Вы не можете отправить заявление самому себе'); + editRecipientPicker.setError('Вы не можете быть получателем'); + return; + } + } + } + const recipients = editRecipientPicker.getValues(); // Добавляем department_ids