feat: в заявке 1С дата запрета по АТП оформляется только на базу АТП
При виде работ «Дата запрета (открытие/закрытие)» и выбранной базе АТП остальные базы снимаются и добавить их нельзя — дата запрета по АТП открывается/закрывается отдельно. Над полем «База 1С» при этом виде работ показывается предупреждение. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,13 @@ export const CHOICES_LOADING_PLACEHOLDER = 'Загрузка вариантов
|
||||
export const CHOICES_EMPTY_PLACEHOLDER = 'Нет вариантов — обратитесь к администратору';
|
||||
export const CHOICES_ERROR_PREFIX = 'Не удалось загрузить варианты полей';
|
||||
|
||||
// Подсказка в поле «База 1С», когда сработало правило «дата запрета по АТП».
|
||||
export const DB1C_ATP_ONLY_HINT = 'Для даты запрета по АТП другие базы не выбираются';
|
||||
// Предупреждение над полем «База 1С» при виде работ «Дата запрета».
|
||||
export const DB1C_ATP_ONLY_WARNING =
|
||||
'Для даты запрета (открытие/закрытие) по базе АТП можно выбрать только АТП — ' +
|
||||
'дополнительные базы недоступны.';
|
||||
|
||||
// Значения из property pane старой web part (см. живую страницу SharePoint).
|
||||
export const PLANNER_PLAN_ID = '168WqDV8CEKkW3cL6olCRZgACwYa';
|
||||
export const PLANNER_BUCKET_NAME = 'Входящие неотсортированные';
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import { DB1C_ATP_OPTION, WORK_TYPE_BAN_DATE, restrictDatabases } from './model';
|
||||
|
||||
const ZUP = '1С: Зарплата и управление персоналом (ЗУП)';
|
||||
|
||||
describe('Ticket1C restrictDatabases', () => {
|
||||
it('дата запрета + АТП — остаётся только АТП', () => {
|
||||
expect(restrictDatabases(WORK_TYPE_BAN_DATE, [ZUP, DB1C_ATP_OPTION])).toEqual([DB1C_ATP_OPTION]);
|
||||
});
|
||||
|
||||
it('дата запрета без АТП — базы не трогаем', () => {
|
||||
expect(restrictDatabases(WORK_TYPE_BAN_DATE, [ZUP])).toEqual([ZUP]);
|
||||
});
|
||||
|
||||
it('другой вид работ — АТП можно сочетать с другими базами', () => {
|
||||
expect(restrictDatabases('Прочее', [ZUP, DB1C_ATP_OPTION])).toEqual([ZUP, DB1C_ATP_OPTION]);
|
||||
});
|
||||
});
|
||||
@@ -44,6 +44,27 @@ export function hasOtherDatabase(data: IFormData): boolean {
|
||||
return data.DB1C.indexOf(DB1C_OTHER_OPTION) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Варианты колонок SP, для которых действует правило «дата запрета по АТП —
|
||||
* только одна база». Должны дословно совпадать с вариантами колонок
|
||||
* WorkType и DB1C в SharePoint (варианты читаются из SP, см. useFieldChoices).
|
||||
*/
|
||||
export const WORK_TYPE_BAN_DATE = 'Дата запрета (открытие/закрытие)';
|
||||
export const DB1C_ATP_OPTION = '1С: Автотранспортное предприятие (АТП)';
|
||||
|
||||
/**
|
||||
* Дата запрета в АТП открывается/закрывается отдельно от остальных баз,
|
||||
* поэтому в такой заявке база АТП может быть только одна.
|
||||
*/
|
||||
export function isAtpOnlyBanDate(workType: string, databases: string[]): boolean {
|
||||
return workType === WORK_TYPE_BAN_DATE && databases.indexOf(DB1C_ATP_OPTION) !== -1;
|
||||
}
|
||||
|
||||
/** Применяет правило isAtpOnlyBanDate: при его срабатывании оставляет только АТП. */
|
||||
export function restrictDatabases(workType: string, databases: string[]): string[] {
|
||||
return isAtpOnlyBanDate(workType, databases) ? [DB1C_ATP_OPTION] : databases;
|
||||
}
|
||||
|
||||
/** Обновление одного поля формы с сохранением типа значения. */
|
||||
export type SetField = <K extends keyof IFormData>(key: K, value: IFormData[K]) => void;
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// Строка на обе колонки сетки секции — как FormField с full.
|
||||
.fullRow {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
@@ -1,10 +1,21 @@
|
||||
import * as React from 'react';
|
||||
import styles from './RequestSection.module.scss';
|
||||
import { Alert, CollapseSection, FormField, MultiChoiceField, Select, TextArea, TextInput, ISelectOption } from '../../../shared/ui';
|
||||
import { useFieldChoices, IFieldChoicesState } from '../../../shared/fieldChoices';
|
||||
import { dataListTitle } from '../../../shared/listTitles';
|
||||
import { DB1C_OTHER_OPTION, FORM_ID, ISectionProps, hasOtherDatabase } from '../model';
|
||||
import {
|
||||
DB1C_OTHER_OPTION,
|
||||
FORM_ID,
|
||||
WORK_TYPE_BAN_DATE,
|
||||
ISectionProps,
|
||||
hasOtherDatabase,
|
||||
isAtpOnlyBanDate,
|
||||
restrictDatabases
|
||||
} from '../model';
|
||||
import {
|
||||
QUESTION_MAX,
|
||||
DB1C_ATP_ONLY_HINT,
|
||||
DB1C_ATP_ONLY_WARNING,
|
||||
CHOICES_LOADING_PLACEHOLDER,
|
||||
CHOICES_EMPTY_PLACEHOLDER,
|
||||
CHOICES_ERROR_PREFIX
|
||||
@@ -30,6 +41,16 @@ export const RequestSection: React.FC<ISectionProps> = ({ data, set }) => {
|
||||
const organizations = useFieldChoices(listTitle, 'Organization');
|
||||
const databases = useFieldChoices(listTitle, 'DB1C');
|
||||
const choicesError = workTypes.error || organizations.error || databases.error;
|
||||
const isAtpOnly = isAtpOnlyBanDate(data.WorkType, data.DB1C);
|
||||
|
||||
// Правило «дата запрета по АТП» зависит и от вида работ, и от баз — поэтому
|
||||
// применяется при смене любого из двух полей.
|
||||
const setDatabases = (workType: string, values: string[]): void => {
|
||||
const restricted = restrictDatabases(workType, values);
|
||||
set('DB1C', restricted);
|
||||
// Сняли «Другое» — вписанное название больше не относится к заявке.
|
||||
if (restricted.indexOf(DB1C_OTHER_OPTION) === -1) set('DB1COther', '');
|
||||
};
|
||||
|
||||
return (
|
||||
<CollapseSection title="Заявка" icon="clipboard">
|
||||
@@ -41,7 +62,10 @@ export const RequestSection: React.FC<ISectionProps> = ({ data, set }) => {
|
||||
<Select
|
||||
id="WorkType"
|
||||
value={data.WorkType}
|
||||
onChange={(v) => set('WorkType', v)}
|
||||
onChange={(v) => {
|
||||
set('WorkType', v);
|
||||
setDatabases(v, data.DB1C);
|
||||
}}
|
||||
options={withCurrentValue(workTypes.options, data.WorkType)}
|
||||
placeholder={choicesPlaceholder(workTypes, '— выберите —')}
|
||||
/>
|
||||
@@ -55,18 +79,22 @@ export const RequestSection: React.FC<ISectionProps> = ({ data, set }) => {
|
||||
placeholder={choicesPlaceholder(organizations, '— выберите —')}
|
||||
/>
|
||||
</FormField>
|
||||
{/* Предупреждаем заранее, ещё до выбора баз, чтобы правило не стало сюрпризом. */}
|
||||
{data.WorkType === WORK_TYPE_BAN_DATE && (
|
||||
<div className={styles.fullRow}>
|
||||
<Alert variant="warn">{DB1C_ATP_ONLY_WARNING}</Alert>
|
||||
</div>
|
||||
)}
|
||||
{/* На всю ширину: чипы выбранных баз растят поле по высоте, и соседнее
|
||||
поле в той же строке сетки съезжало бы относительно него. */}
|
||||
<FormField label="База 1С" fieldKey="DB1C" required full>
|
||||
<MultiChoiceField
|
||||
value={data.DB1C}
|
||||
onChange={(v) => {
|
||||
set('DB1C', v);
|
||||
// Сняли «Другое» — вписанное название больше не относится к заявке.
|
||||
if (v.indexOf(DB1C_OTHER_OPTION) === -1) set('DB1COther', '');
|
||||
}}
|
||||
options={databases.options}
|
||||
placeholder={choicesPlaceholder(databases, 'Выберите одну или несколько баз')}
|
||||
onChange={(v) => setDatabases(data.WorkType, v)}
|
||||
// Пустой список вариантов прячет выпадашку — добавить другую базу нельзя,
|
||||
// пока не уберут АТП или не сменят вид работ.
|
||||
options={isAtpOnly ? [] : databases.options}
|
||||
placeholder={isAtpOnly ? DB1C_ATP_ONLY_HINT : choicesPlaceholder(databases, 'Выберите одну или несколько баз')}
|
||||
/>
|
||||
</FormField>
|
||||
{hasOtherDatabase(data) && (
|
||||
|
||||
Reference in New Issue
Block a user