fix: отпуск без содержания — без лимита 5 дней, «Иная причина»
5 дней работодатель обязан дать только при браке/рождении/смерти, сверх — по договорённости, поэтому форма больше не ограничивает число дней. Вариант «В иных случаях» подписан как «Иная причина» — читается как ответ на «Причина»; значение в SP прежнее. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,10 +22,11 @@
|
|||||||
- **Период вводится двумя датами** (с / по), обе обязательны, конец ≥ начала.
|
- **Период вводится двумя датами** (с / по), обе обязательны, конец ≥ начала.
|
||||||
`DaysCount` считается при сохранении (включительно) для отчётности — в UI не показывается.
|
`DaysCount` считается при сохранении (включительно) для отчётности — в UI не показывается.
|
||||||
- **Причина** (`UnpaidLeaveReasonType`, Choice) — обязательна: брак / рождение ребёнка /
|
- **Причина** (`UnpaidLeaveReasonType`, Choice) — обязательна: брак / рождение ребёнка /
|
||||||
смерть близких / «В иных случаях». Только при «иных случаях» появляется обязательный
|
смерть близких / «В иных случаях» (в форме подписано «Иная причина», значение в SP прежнее). Только при «иных случаях» появляется обязательный
|
||||||
текст причины (`Reason`). У заявок до появления колонки причины нет — их прежний
|
текст причины (`Reason`). У заявок до появления колонки причины нет — их прежний
|
||||||
текст из `Reason` по-прежнему показывается (`isReasonTextShown`).
|
текст из `Reason` по-прежнему показывается (`isReasonTextShown`).
|
||||||
- **Не более 5 календарных дней** (`MAX_DAYS`) — при любой причине.
|
- **Количество дней без верхнего предела** — 5 дней работодатель обязан дать при браке /
|
||||||
|
рождении / смерти, остальное — по договорённости, поэтому форма лимит не ставит.
|
||||||
- **Правило «не позднее чем за 14 дней»** (`MIN_NOTICE_DAYS`) — только для «иных случаев»
|
- **Правило «не позднее чем за 14 дней»** (`MIN_NOTICE_DAYS`) — только для «иных случаев»
|
||||||
(`requiresAdvanceNotice`): брак, рождение и смерть заранее не планируются.
|
(`requiresAdvanceNotice`): брак, рождение и смерть заранее не планируются.
|
||||||
- **Подсветка проблемных полей** — `FieldIssuesProvider` + правила в `validation.ts`
|
- **Подсветка проблемных полей** — `FieldIssuesProvider` + правила в `validation.ts`
|
||||||
|
|||||||
@@ -94,8 +94,6 @@ export const SUBSTITUTE_PLACEHOLDER = 'Начните вводить Ф.И.О.
|
|||||||
* Действует только для «иных случаев» — см. requiresAdvanceNotice.
|
* Действует только для «иных случаев» — см. requiresAdvanceNotice.
|
||||||
*/
|
*/
|
||||||
export const MIN_NOTICE_DAYS = 14;
|
export const MIN_NOTICE_DAYS = 14;
|
||||||
/** Отпуск без сохранения заработной платы — не более стольких календарных дней (по любой причине). */
|
|
||||||
export const MAX_DAYS = 5;
|
|
||||||
|
|
||||||
/** Причины отпуска. Значения совпадают с choices колонки UnpaidLeaveReasonType. */
|
/** Причины отпуска. Значения совпадают с choices колонки UnpaidLeaveReasonType. */
|
||||||
export const REASON_MARRIAGE = 'Регистрация брака';
|
export const REASON_MARRIAGE = 'Регистрация брака';
|
||||||
@@ -108,7 +106,8 @@ export const UNPAID_LEAVE_REASONS: ISelectOption[] = [
|
|||||||
{ value: REASON_MARRIAGE, label: REASON_MARRIAGE },
|
{ value: REASON_MARRIAGE, label: REASON_MARRIAGE },
|
||||||
{ value: REASON_CHILD_BIRTH, label: REASON_CHILD_BIRTH },
|
{ value: REASON_CHILD_BIRTH, label: REASON_CHILD_BIRTH },
|
||||||
{ value: REASON_RELATIVE_DEATH, label: REASON_RELATIVE_DEATH },
|
{ value: REASON_RELATIVE_DEATH, label: REASON_RELATIVE_DEATH },
|
||||||
{ value: REASON_OTHER, label: REASON_OTHER }
|
// Значение в SP остаётся прежним (choices колонки и старые заявки), меняется только подпись.
|
||||||
|
{ value: REASON_OTHER, label: 'Иная причина' }
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
EMPLOYEE_PLACEHOLDER,
|
EMPLOYEE_PLACEHOLDER,
|
||||||
SUBSTITUTE_PLACEHOLDER,
|
SUBSTITUTE_PLACEHOLDER,
|
||||||
MIN_NOTICE_DAYS,
|
MIN_NOTICE_DAYS,
|
||||||
MAX_DAYS,
|
|
||||||
REASON_OTHER,
|
REASON_OTHER,
|
||||||
UNPAID_LEAVE_REASONS,
|
UNPAID_LEAVE_REASONS,
|
||||||
requiresAdvanceNotice,
|
requiresAdvanceNotice,
|
||||||
@@ -61,14 +60,13 @@ export const RequestSection: React.FC<ISectionProps> = ({ data, set, context, on
|
|||||||
min={requiresAdvanceNotice(data.ReasonType) ? isoDatePlusDays(MIN_NOTICE_DAYS) : undefined}
|
min={requiresAdvanceNotice(data.ReasonType) ? isoDatePlusDays(MIN_NOTICE_DAYS) : undefined}
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
<FormField label={`Количество дней (не более ${MAX_DAYS})`} htmlFor="DaysCount" required>
|
<FormField label="Количество дней" htmlFor="DaysCount" required>
|
||||||
<TextInput
|
<TextInput
|
||||||
id="DaysCount"
|
id="DaysCount"
|
||||||
type="number"
|
type="number"
|
||||||
value={data.DaysCount}
|
value={data.DaysCount}
|
||||||
onChange={(v) => set('DaysCount', v)}
|
onChange={(v) => set('DaysCount', v)}
|
||||||
min={1}
|
min={1}
|
||||||
max={MAX_DAYS}
|
|
||||||
/>
|
/>
|
||||||
</FormField>
|
</FormField>
|
||||||
<FormField label="Причина" htmlFor="UnpaidLeaveReasonType" required full>
|
<FormField label="Причина" htmlFor="UnpaidLeaveReasonType" required full>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { IFieldIssue } from '../../shared/ui';
|
import type { IFieldIssue } from '../../shared/ui';
|
||||||
import { isoDatePlusDays, formatIsoDate } from '../../shared/dateUtils';
|
import { isoDatePlusDays, formatIsoDate } from '../../shared/dateUtils';
|
||||||
import { IFormData, MAX_DAYS, MIN_NOTICE_DAYS, REASON_OTHER, requiresAdvanceNotice } from './model';
|
import { IFormData, MIN_NOTICE_DAYS, REASON_OTHER, requiresAdvanceNotice } from './model';
|
||||||
|
|
||||||
/** Дата начала: обязательна, а в «иных случаях» — не раньше чем через MIN_NOTICE_DAYS дней. */
|
/** Дата начала: обязательна, а в «иных случаях» — не раньше чем через MIN_NOTICE_DAYS дней. */
|
||||||
function startDateIssue(data: IFormData): IFieldIssue | undefined {
|
function startDateIssue(data: IFormData): IFieldIssue | undefined {
|
||||||
@@ -12,17 +12,20 @@ function startDateIssue(data: IFormData): IFieldIssue | undefined {
|
|||||||
return {
|
return {
|
||||||
field: 'StartDate',
|
field: 'StartDate',
|
||||||
label: 'Дата начала',
|
label: 'Дата начала',
|
||||||
message: `в иных случаях заявление подают не позднее чем за ${MIN_NOTICE_DAYS} дней — не раньше ${formatIsoDate(minStartDate)}`
|
message: `при иной причине заявление подают не позднее чем за ${MIN_NOTICE_DAYS} дней — не раньше ${formatIsoDate(minStartDate)}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Количество дней: обязательно, от 1 до MAX_DAYS. */
|
/**
|
||||||
|
* Количество дней: обязательно, целое и больше нуля. Верхнего предела нет:
|
||||||
|
* сверх 5 дней (обязательных при браке/рождении/смерти) — по договорённости с работодателем.
|
||||||
|
*/
|
||||||
function daysCountIssue(data: IFormData): IFieldIssue | undefined {
|
function daysCountIssue(data: IFormData): IFieldIssue | undefined {
|
||||||
if (!data.DaysCount.trim()) return { field: 'DaysCount', label: 'Количество дней' };
|
if (!data.DaysCount.trim()) return { field: 'DaysCount', label: 'Количество дней' };
|
||||||
|
|
||||||
const days = Number(data.DaysCount);
|
const days = Number(data.DaysCount);
|
||||||
if (Number.isFinite(days) && days > 0 && days <= MAX_DAYS) return undefined;
|
if (Number.isInteger(days) && days > 0) return undefined;
|
||||||
return { field: 'DaysCount', label: 'Количество дней', message: `от 1 до ${MAX_DAYS} календарных дней` };
|
return { field: 'DaysCount', label: 'Количество дней', message: 'целое число больше нуля' };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user