feat: один общий комментарий к списанию вместо шести, «Подразделение» вместо «Структурное»
Обходной лист: 6 отдельных Comment-колонок (по одной на категорию списания) консолидированы в одну WriteOffComment — комментарий и так один по смыслу («за что списываем»), дублировать текст в 6 колонок не было смысла. IWriteOffCategory больше не хранит commentField, WriteOffFieldKey сузился до 6 сумм. Заявление на увольнение: заголовок колонки таблицы организаций — «Подразделение» вместо «Структурное подразделение» (данные по-прежнему из Section справочника, только подпись короче). Со схемой ничего руками не делал — команда для провижининга ниже. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -45,7 +45,7 @@
|
||||
| [`recruiting-referral`](../src/webparts/requestPortal/forms/Referral/README.md) | Реферальная рекомендация | Рекрутинг | да | да | да | кандидат — внешний (текстовые поля, не People); маршрут по рекомендателю; исполнитель переназначает на реального; условное уточнение «откуда знаете» | ✅ |
|
||||
| [`it-workplace-setup`](../src/webparts/requestPortal/forms/WorkplaceSetup/README.md) | Организация рабочего места | IT | да | да | да | префилл из «прием», поля ПО/доступы правит руководитель | ✅ |
|
||||
| [`it-1c-ticket`](../src/webparts/requestPortal/forms/Ticket1C/README.md) | Заявка в отдел 1С | IT | да | нет | да | контакты предзаполняются из Graph (/me); вместо фазы исполнения — карточка в Microsoft Planner (согласовано/сразу без согласования — рабочий бакет, отклонено — отдельный бакет) | ✅ |
|
||||
| [`clearance-form`](../src/webparts/requestPortal/forms/Clearance/README.md) | Обходной лист | Отдел кадров | да | нет | да | подаётся HR за увольняемого (People-picker) либо создаётся сам по согласованному «Заявлению на увольнение»; условие «IsManager» резолвится по должности из самой заявки; да/нет-поля (парковка, СКУД); 6 независимых сумм к списанию компактной сеткой (ОС, СИЗ, подотчётная сумма, обучение, НМА, ТМЦ) — вводит любой активный согласующий, блокируется навсегда после первого ввода; заполнил хоть одну — общий комментарий «за что» становится обязательным | ✅ |
|
||||
| [`clearance-form`](../src/webparts/requestPortal/forms/Clearance/README.md) | Обходной лист | Отдел кадров | да | нет | да | подаётся HR за увольняемого (People-picker) либо создаётся сам по согласованному «Заявлению на увольнение»; условие «IsManager» резолвится по должности из самой заявки; да/нет-поля (парковка, СКУД); 6 независимых сумм к списанию компактной сеткой (ОС, СИЗ, подотчётная сумма, обучение, НМА, ТМЦ) — вводит любой активный согласующий, блокируется навсегда после первого ввода; заполнил хоть одну — ОДИН общий комментарий «за что» становится обязательным | ✅ |
|
||||
| [`hr-dismissal`](../src/webparts/requestPortal/forms/Dismissal/README.md) | Заявление на увольнение | Отдел кадров | да | нет | да | совместители — таблица компаний с удалением строки (снимает и согласующего из матрицы); должность/организация из справочника; **после согласования сам создаёт обходной лист**; печать заблокирована до согласования обходного листа; «Лицо, принимающее ОС/НМА» — заполняет только непосредственный руководитель | ✅ |
|
||||
| `hr-transfer` | Перемещение сотрудников | Отдел кадров | — | — | — | — | ⏳ заглушка (плитка есть, форма не сделана) |
|
||||
|
||||
|
||||
@@ -172,11 +172,9 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
|
||||
// Пишем ТОЛЬКО те отметки, на которые у согласующего есть права: иначе он
|
||||
// затёр бы чужие поля значениями, которые видел у себя на экране. Суммы к
|
||||
// списанию — только НЕПУСТЫЕ и только среди editableWriteOffKeys; комментарий
|
||||
// ОДИН на все суммы, заполняемые СЕЙЧАС (не пара на каждую, см. IFormData.
|
||||
// WriteOffComment) — если хоть одна из них не пуста, комментарий обязателен
|
||||
// (бросает ДО записи чего бы то ни было) и при записи дублируется в
|
||||
// Comment-колонку КАЖДОЙ такой категории — так каждая остаётся
|
||||
// прокомментированной в самом списке.
|
||||
// ОДИН на все суммы (IFormData.WriteOffComment, не пара на каждую категорию)
|
||||
// — если хоть одна из редактируемых сумм не пуста, комментарий обязателен
|
||||
// (бросает ДО записи чего бы то ни было).
|
||||
const saveApproverFields = useCallback(async (): Promise<void> => {
|
||||
const fields: Partial<IApproverEditableFields> = {};
|
||||
if (hrRecordsEditable) {
|
||||
@@ -198,8 +196,8 @@ const ClearanceView: React.FC<IClearanceViewProps> = ({ context, itemId, formKey
|
||||
}
|
||||
for (const cat of touched) {
|
||||
writeOffFields[cat.amountField] = data[cat.amountField];
|
||||
writeOffFields[cat.commentField] = comment;
|
||||
}
|
||||
writeOffFields.WriteOffComment = comment;
|
||||
}
|
||||
|
||||
await updateApproverFields(itemId, fields, listId);
|
||||
|
||||
@@ -55,10 +55,10 @@ RequestTypeId» в `docs/forms.md`). Тип уже зарегистрирова
|
||||
заведённых руками, ссылки нет и поле не рендерится.
|
||||
|
||||
## Суммы к списанию (согласование)
|
||||
6 НЕЗАВИСИМЫХ сумм, компактной сеткой (короткие подписи, без комментария под
|
||||
каждой — см. ниже), колонки `WriteOff{Assets,Ppe,Accountable,Training,Nma,Tmc}
|
||||
{Amount,Comment}` (см. `model.ts WRITE_OFF_CATEGORIES`): «ОС», «СИЗ», «Подотчётная
|
||||
сумма», «Обучение», «НМА», «ТМЦ».
|
||||
6 НЕЗАВИСИМЫХ сумм, компактной сеткой (короткие подписи, обычная 2-колоночная
|
||||
сетка секции), колонки `WriteOff{Assets,Ppe,Accountable,Training,Nma,Tmc}Amount`
|
||||
(см. `model.ts WRITE_OFF_CATEGORIES`): «ОС», «СИЗ», «Подотчётная сумма»,
|
||||
«Обучение», «НМА», «ТМЦ». Плюс ОДИН общий комментарий на всех — `WriteOffComment`.
|
||||
|
||||
- **Не привязаны к должности**, в отличие от отметок выше: заполнить может ЛЮБОЙ
|
||||
согласующий, у которого сейчас активный шаг (`ClearanceView.canEditWriteOffs`,
|
||||
@@ -68,15 +68,16 @@ RequestTypeId» в `docs/forms.md`). Тип уже зарегистрирова
|
||||
Признак блокировки — сама непустая сумма на МОМЕНТ ЗАГРУЗКИ страницы
|
||||
(`ClearanceView.lockedWriteOffs`, снимок при загрузке, а не реактивно от
|
||||
текущего `data` — иначе поле блокировалось бы прямо во время набора цифр).
|
||||
- **Комментарий — ОДИН на все суммы, заполняемые в ЭТОМ сохранении** (не пара на
|
||||
каждую категорию, как раньше): появляется под сеткой, только когда хоть одна
|
||||
редактируемая сумма не пуста (`writeOffTouchedCategories` в `RequestSection`),
|
||||
и обязателен в этот момент — `saveApproverFields` бросает ДО записи чего бы то
|
||||
ни было, если сумма есть, а комментарий пуст. Плейсхолдер называет категории,
|
||||
для которых он сейчас пишется («Введите, за что сумма: ОС, ТМЦ»). При записи
|
||||
этот ОДИН текст дублируется в Comment-колонку КАЖДОЙ заполняемой сейчас
|
||||
категории — так индивидуальный комментарий по категории в списке остаётся, а
|
||||
форма не заставляет писать одно и то же под каждой суммой отдельно.
|
||||
- **Комментарий («за что конкретно») — ОДИН на ВСЕ суммы**, не пара на каждую
|
||||
категорию: одна Note-колонка (`WriteOffComment`), не шесть. Read-only, пока
|
||||
нечего заполнять (показывает то, что уже написали раньше); становится
|
||||
редактируемым и ОБЯЗАТЕЛЬНЫМ ровно тогда, когда хоть одна редактируемая сумма
|
||||
не пуста (`writeOffTouchedCategories` в `RequestSection`) — `saveApproverFields`
|
||||
бросает ДО записи чего бы то ни было, если сумма есть, а комментарий пуст.
|
||||
Плейсхолдер называет категории, для которых он сейчас пишется («Введите, за
|
||||
что сумма: ОС, ТМЦ»). Следующий согласующий, заполняющий ДРУГУЮ сумму, увидит
|
||||
и сможет дописать то, что уже есть в поле, — это обычный редактируемый текст,
|
||||
без автоматического версионирования/склейки.
|
||||
- Сохраняются той же кнопкой «Сохранить» (`reviewBar`), что и остальные отметки,
|
||||
и тем же `onBeforeDecide` — при решении несохранённые суммы уйдут вместе с ним.
|
||||
- Это ОТДЕЛЬНЫЙ механизм от `TrainingAmount` («Обучение: сумма» выше, привязана к
|
||||
|
||||
@@ -39,17 +39,12 @@ export async function loadClearanceRequest(itemId: number, listId?: string): Pro
|
||||
'Organization',
|
||||
'DismissalUrl',
|
||||
'WriteOffAssetsAmount',
|
||||
'WriteOffAssetsComment',
|
||||
'WriteOffPpeAmount',
|
||||
'WriteOffPpeComment',
|
||||
'WriteOffAccountableAmount',
|
||||
'WriteOffAccountableComment',
|
||||
'WriteOffTrainingAmount',
|
||||
'WriteOffTrainingComment',
|
||||
'WriteOffNmaAmount',
|
||||
'WriteOffNmaComment',
|
||||
'WriteOffTmcAmount',
|
||||
'WriteOffTmcComment',
|
||||
'WriteOffComment',
|
||||
'RequestStatus',
|
||||
'RequestUniqueCode',
|
||||
'Employee/Title',
|
||||
@@ -74,17 +69,12 @@ export async function loadClearanceRequest(itemId: number, listId?: string): Pro
|
||||
// Гиперссылка приходит объектом {Url, Description} — модели нужен только адрес.
|
||||
DismissalUrl: (item.DismissalUrl as { Url?: string } | undefined)?.Url || '',
|
||||
WriteOffAssetsAmount: numberField(item.WriteOffAssetsAmount),
|
||||
WriteOffAssetsComment: (item.WriteOffAssetsComment as string) || '',
|
||||
WriteOffPpeAmount: numberField(item.WriteOffPpeAmount),
|
||||
WriteOffPpeComment: (item.WriteOffPpeComment as string) || '',
|
||||
WriteOffAccountableAmount: numberField(item.WriteOffAccountableAmount),
|
||||
WriteOffAccountableComment: (item.WriteOffAccountableComment as string) || '',
|
||||
WriteOffTrainingAmount: numberField(item.WriteOffTrainingAmount),
|
||||
WriteOffTrainingComment: (item.WriteOffTrainingComment as string) || '',
|
||||
WriteOffNmaAmount: numberField(item.WriteOffNmaAmount),
|
||||
WriteOffNmaComment: (item.WriteOffNmaComment as string) || '',
|
||||
WriteOffTmcAmount: numberField(item.WriteOffTmcAmount),
|
||||
WriteOffTmcComment: (item.WriteOffTmcComment as string) || ''
|
||||
WriteOffComment: (item.WriteOffComment as string) || ''
|
||||
};
|
||||
|
||||
return {
|
||||
|
||||
@@ -46,80 +46,52 @@ export interface IFormData {
|
||||
* ClearanceView.canEditWriteOffs), но как только сумма непустая — блокируется
|
||||
* НАВСЕГДА, для всех (включая того, кто её ввёл). Признак блокировки — сама
|
||||
* непустая сумма, отдельного флага в списке нет.
|
||||
*
|
||||
* Комментарий («за что конкретно») — ОБЩИЙ на все суммы, вводимые ОДНИМ
|
||||
* сохранением (WriteOffComment, ниже), не отдельная пара на каждую категорию:
|
||||
* при записи он дублируется в Comment-колонку КАЖДОЙ категории, чью сумму
|
||||
* заполнили именно сейчас (см. ClearanceView.saveApproverFields) — так каждая
|
||||
* категория остаётся комментированной в самом списке, а форма не заставляет
|
||||
* писать одно и то же по кругу под каждой суммой.
|
||||
*/
|
||||
WriteOffAssetsAmount: string;
|
||||
WriteOffAssetsComment: string;
|
||||
WriteOffPpeAmount: string;
|
||||
WriteOffPpeComment: string;
|
||||
WriteOffAccountableAmount: string;
|
||||
WriteOffAccountableComment: string;
|
||||
WriteOffTrainingAmount: string;
|
||||
WriteOffTrainingComment: string;
|
||||
WriteOffNmaAmount: string;
|
||||
WriteOffNmaComment: string;
|
||||
WriteOffTmcAmount: string;
|
||||
WriteOffTmcComment: string;
|
||||
/**
|
||||
* Комментарий к сумме(ам), заполняемым ПРЯМО СЕЙЧАС (не из списка — вводится
|
||||
* заново при каждом сохранении, см. комментарий выше). Обязателен, если хоть
|
||||
* одна из редактируемых сумм не пуста (см. RequestSection).
|
||||
* Комментарий «за что конкретно» — ОДИН на ВСЕ суммы к списанию (не пара на
|
||||
* каждую категорию — раньше было так, но колонок-комментариев на каждую
|
||||
* категорию не завели: одного общего достаточно). Обязателен, если хоть одна
|
||||
* из РЕДАКТИРУЕМЫХ сумм не пуста (см. RequestSection.writeOffTouchedCategories),
|
||||
* и до этого момента read-only — показывает то, что уже написали раньше.
|
||||
*/
|
||||
WriteOffComment: string;
|
||||
}
|
||||
|
||||
/** Имена всех 12 строковых полей сумм/комментариев к списанию — см. IFormData.WriteOff*. */
|
||||
/** Имена всех 6 сумм к списанию — см. IFormData.WriteOff*Amount. */
|
||||
export type WriteOffFieldKey =
|
||||
| 'WriteOffAssetsAmount'
|
||||
| 'WriteOffAssetsComment'
|
||||
| 'WriteOffPpeAmount'
|
||||
| 'WriteOffPpeComment'
|
||||
| 'WriteOffAccountableAmount'
|
||||
| 'WriteOffAccountableComment'
|
||||
| 'WriteOffTrainingAmount'
|
||||
| 'WriteOffTrainingComment'
|
||||
| 'WriteOffNmaAmount'
|
||||
| 'WriteOffNmaComment'
|
||||
| 'WriteOffTmcAmount'
|
||||
| 'WriteOffTmcComment';
|
||||
| 'WriteOffTmcAmount';
|
||||
|
||||
/**
|
||||
* Одна из 6 независимых категорий списания — см. IFormData.WriteOff*.
|
||||
* amountField/commentField сужены до WriteOffFieldKey (а не keyof IFormData
|
||||
* целиком): у IFormData есть и булевы поля (ParkingCard/AccessCard), и
|
||||
* `data[cat.amountField]` должен типизироваться строго строкой — иначе
|
||||
* `.trim()` в валидации и передача в MoneyInput/TextArea не собираются.
|
||||
* Одна из 6 независимых категорий списания — см. IFormData.WriteOff*Amount.
|
||||
* amountField сужен до WriteOffFieldKey (а не keyof IFormData целиком): у
|
||||
* IFormData есть и булевы поля (ParkingCard/AccessCard), и `data[cat.amountField]`
|
||||
* должен типизироваться строго строкой — иначе `.trim()` в валидации и
|
||||
* передача в MoneyInput не собираются.
|
||||
*/
|
||||
export interface IWriteOffCategory {
|
||||
key: string;
|
||||
label: string;
|
||||
amountField: WriteOffFieldKey;
|
||||
commentField: WriteOffFieldKey;
|
||||
}
|
||||
|
||||
export const WRITE_OFF_CATEGORIES: IWriteOffCategory[] = [
|
||||
{ key: 'assets', label: 'ОС', amountField: 'WriteOffAssetsAmount', commentField: 'WriteOffAssetsComment' },
|
||||
{ key: 'ppe', label: 'СИЗ', amountField: 'WriteOffPpeAmount', commentField: 'WriteOffPpeComment' },
|
||||
{
|
||||
key: 'accountable',
|
||||
label: 'Подотчётная сумма',
|
||||
amountField: 'WriteOffAccountableAmount',
|
||||
commentField: 'WriteOffAccountableComment'
|
||||
},
|
||||
{
|
||||
key: 'training',
|
||||
label: 'Обучение',
|
||||
amountField: 'WriteOffTrainingAmount',
|
||||
commentField: 'WriteOffTrainingComment'
|
||||
},
|
||||
{ key: 'nma', label: 'НМА', amountField: 'WriteOffNmaAmount', commentField: 'WriteOffNmaComment' },
|
||||
{ key: 'tmc', label: 'ТМЦ', amountField: 'WriteOffTmcAmount', commentField: 'WriteOffTmcComment' }
|
||||
{ key: 'assets', label: 'ОС', amountField: 'WriteOffAssetsAmount' },
|
||||
{ key: 'ppe', label: 'СИЗ', amountField: 'WriteOffPpeAmount' },
|
||||
{ key: 'accountable', label: 'Подотчётная сумма', amountField: 'WriteOffAccountableAmount' },
|
||||
{ key: 'training', label: 'Обучение', amountField: 'WriteOffTrainingAmount' },
|
||||
{ key: 'nma', label: 'НМА', amountField: 'WriteOffNmaAmount' },
|
||||
{ key: 'tmc', label: 'ТМЦ', amountField: 'WriteOffTmcAmount' }
|
||||
];
|
||||
|
||||
/** Обновление одного поля формы с сохранением типа значения. */
|
||||
@@ -148,17 +120,11 @@ export const EMPTY_DATA: IFormData = {
|
||||
Organization: '',
|
||||
DismissalUrl: '',
|
||||
WriteOffAssetsAmount: '',
|
||||
WriteOffAssetsComment: '',
|
||||
WriteOffPpeAmount: '',
|
||||
WriteOffPpeComment: '',
|
||||
WriteOffAccountableAmount: '',
|
||||
WriteOffAccountableComment: '',
|
||||
WriteOffTrainingAmount: '',
|
||||
WriteOffTrainingComment: '',
|
||||
WriteOffNmaAmount: '',
|
||||
WriteOffNmaComment: '',
|
||||
WriteOffTmcAmount: '',
|
||||
WriteOffTmcComment: '',
|
||||
WriteOffComment: ''
|
||||
};
|
||||
|
||||
|
||||
@@ -17,16 +17,11 @@
|
||||
{ "internalName": "DismissalUrl", "title": "Ссылка на заявление на увольнение", "type": "Url" },
|
||||
|
||||
{ "internalName": "WriteOffAssetsAmount", "title": "Сумма к списанию: ОС", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffAssetsComment", "title": "Комментарий: ОС", "type": "Note" },
|
||||
{ "internalName": "WriteOffPpeAmount", "title": "Сумма к списанию: СИЗ", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffPpeComment", "title": "Комментарий: СИЗ", "type": "Note" },
|
||||
{ "internalName": "WriteOffAccountableAmount", "title": "Сумма к списанию: подотчётная сумма", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffAccountableComment", "title": "Комментарий: подотчётная сумма", "type": "Note" },
|
||||
{ "internalName": "WriteOffTrainingAmount", "title": "Сумма к списанию: обучение", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffTrainingComment", "title": "Комментарий: обучение", "type": "Note" },
|
||||
{ "internalName": "WriteOffNmaAmount", "title": "Сумма к списанию: НМА", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffNmaComment", "title": "Комментарий: НМА", "type": "Note" },
|
||||
{ "internalName": "WriteOffTmcAmount", "title": "Сумма к списанию: ТМЦ", "type": "Number", "decimals": 2 },
|
||||
{ "internalName": "WriteOffTmcComment", "title": "Комментарий: ТМЦ", "type": "Note" }
|
||||
{ "internalName": "WriteOffComment", "title": "Комментарий к списанию", "type": "Note" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ export const RequestSection: React.FC<IRequestSectionProps> = ({
|
||||
от отметок выше) — но как только сумма указана, блокируется навсегда
|
||||
для всех, поэтому у незаблокированных (writeOffEditableKeys.has(cat.key))
|
||||
есть readOnly={false}, у остальных — обычное поведение FormMode
|
||||
(просмотр — заблокировано и так). Комментарий — ОДИН на все суммы,
|
||||
вводимые сейчас (см. WRITE_OFF_CATEGORIES/WriteOffComment в model.ts). */}
|
||||
(просмотр — заблокировано и так). Комментарий — ОДИН на ВСЕ суммы
|
||||
(не пара на каждую категорию, см. IFormData.WriteOffComment). */}
|
||||
{writeOffEditableKeys && (
|
||||
<>
|
||||
{WRITE_OFF_CATEGORIES.map((cat) => {
|
||||
@@ -129,15 +129,28 @@ export const RequestSection: React.FC<IRequestSectionProps> = ({
|
||||
</FormField>
|
||||
);
|
||||
})}
|
||||
{writeOffTouchedCategories.length > 0 && (
|
||||
<FormField label="Комментарий: за что списание" htmlFor="WriteOffComment" required full>
|
||||
{/* Read-only, если сейчас нечего заполнять (нет свежих сумм) — просто
|
||||
показывает, что написали раньше; редактируема и обязательна
|
||||
ровно тогда, когда есть непустая сумма, которую надо объяснить. */}
|
||||
{(writeOffTouchedCategories.length > 0 || data.WriteOffComment) && (
|
||||
<FormField
|
||||
label="Комментарий: за что списание"
|
||||
htmlFor="WriteOffComment"
|
||||
required={writeOffTouchedCategories.length > 0}
|
||||
full
|
||||
>
|
||||
<TextArea
|
||||
id="WriteOffComment"
|
||||
value={data.WriteOffComment}
|
||||
onChange={(v) => set('WriteOffComment', v)}
|
||||
placeholder={`Введите, за что сумма${
|
||||
writeOffTouchedCategories.length > 1 ? 'ы' : ''
|
||||
}: ${writeOffTouchedCategories.map((c) => c.label).join(', ')}`}
|
||||
readOnly={writeOffTouchedCategories.length > 0 ? false : true}
|
||||
placeholder={
|
||||
writeOffTouchedCategories.length > 0
|
||||
? `Введите, за что сумма${
|
||||
writeOffTouchedCategories.length > 1 ? 'ы' : ''
|
||||
}: ${writeOffTouchedCategories.map((c) => c.label).join(', ')}`
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</FormField>
|
||||
)}
|
||||
|
||||
@@ -3,18 +3,18 @@ import { ISaveItemResult, resolveDataList, saveRequestItem } from '../../shared/
|
||||
import { ensureEmployee } from '../../shared/employee';
|
||||
import { FORM_ID, IFormData, WriteOffFieldKey } from './model';
|
||||
|
||||
/** Одна из 12 колонок сумм/комментариев к списанию — см. model.ts WRITE_OFF_CATEGORIES. */
|
||||
export type IWriteOffFields = Pick<IFormData, WriteOffFieldKey>;
|
||||
/** 6 сумм к списанию + общий комментарий — см. model.ts WRITE_OFF_CATEGORIES/IFormData.WriteOffComment. */
|
||||
export type IWriteOffFields = Pick<IFormData, WriteOffFieldKey | 'WriteOffComment'>;
|
||||
|
||||
/**
|
||||
* Записать сумму(ы)/комментарий(и) к списанию. Пишет РОВНО переданные поля —
|
||||
* как updateApproverFields, каждая пара независима.
|
||||
* Записать сумму(ы) к списанию и/или общий комментарий. Пишет РОВНО переданные
|
||||
* поля — как updateApproverFields, каждое независимо.
|
||||
*
|
||||
* ВАЖНО: вызывающая сторона (ClearanceView) обязана передавать сюда ТОЛЬКО те
|
||||
* пары, что ещё не заблокированы (см. IFormData.WriteOff* — блокировка по
|
||||
* непустой сумме) и заполнены целиком (сумма+комментарий вместе, см.
|
||||
* validateWriteOffPairs) — эта функция сама повторно ничего не проверяет и
|
||||
* молча перезапишет то, что ей передали.
|
||||
* ВАЖНО: вызывающая сторона (ClearanceView) обязана передавать сюда ТОЛЬКО ещё
|
||||
* не заблокированные суммы (см. IFormData.WriteOff* — блокировка по непустой
|
||||
* сумме) и проверенный (непустой, если хоть одна сумма заполняется) комментарий
|
||||
* — эта функция сама повторно ничего не проверяет и молча перезапишет то, что
|
||||
* ей передали.
|
||||
*/
|
||||
export async function updateWriteOffFields(
|
||||
id: number,
|
||||
|
||||
@@ -36,7 +36,7 @@ RequestTypeId» в `docs/forms.md`). Тип заведён в админке app
|
||||
отдельных полей для них нет (были бы дублированием). `data.Organization:
|
||||
IOrganizationRecord[]` — массив `{company, department, position}`; поле называется
|
||||
`department` (тот же справочник `Section`, что и раньше — см. следующий абзац),
|
||||
колонка называется «Структурное подразделение», и то и другое read-only. Должность
|
||||
колонка называется «Подразделение», и то и другое read-only. Должность
|
||||
редактируема В ЛЮБОЙ строке (справочник не всегда точен), но маршрут (условие
|
||||
«IsManager») и обязательность по валидации завязаны ТОЛЬКО на должность ПЕРВОЙ
|
||||
(основной) записи — `primaryPosition(data.Organization)`; должности остальных
|
||||
|
||||
@@ -56,7 +56,7 @@ export const OrganizationsTable: React.FC<IOrganizationsTableProps> = ({ records
|
||||
<thead>
|
||||
<tr>
|
||||
<th className={styles.company}>Компания</th>
|
||||
<th className={styles.department}>Структурное подразделение</th>
|
||||
<th className={styles.department}>Подразделение</th>
|
||||
<th className={styles.position}>Должность</th>
|
||||
{onRemove && <th className={styles.action} />}
|
||||
</tr>
|
||||
|
||||
Reference in New Issue
Block a user