рефакторинг
This commit is contained in:
@@ -1,21 +1,15 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, resolveDataList, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
import { ensureEmployee } from '../../shared/employee';
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function clearanceApprovalService(listId?: string): ApprovalListService {
|
export function clearanceApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Отметки, которые проставляет не инициатор, а профильный согласующий (см. approverRights.ts). */
|
/** Отметки, которые проставляет не инициатор, а профильный согласующий (см. approverRights.ts). */
|
||||||
@@ -47,16 +41,10 @@ export async function updateApproverFields(
|
|||||||
Number.isFinite(amount) && fields.TrainingAmount.trim() !== '' ? amount : null;
|
Number.isFinite(amount) && fields.TrainingAmount.trim() !== '' ? amount : null;
|
||||||
}
|
}
|
||||||
if (Object.keys(item).length === 0) return;
|
if (Object.keys(item).length === 0) return;
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
const list = resolveDataList(FORM_ID, listId);
|
||||||
await list.items.getById(id).update(item);
|
await list.items.getById(id).update(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** email / claims-логин → пользователь сайта (Id для Person-поля + Title для заголовка). */
|
|
||||||
async function ensureEmployee(login: string): Promise<{ Id: number; Title: string }> {
|
|
||||||
const full = login.indexOf('|') >= 0 ? login : `i:0#.f|membership|${login}`;
|
|
||||||
return getSP().web.ensureUser(full);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pad2(n: number): string {
|
function pad2(n: number): string {
|
||||||
return n < 10 ? `0${n}` : `${n}`;
|
return n < 10 ? `0${n}` : `${n}`;
|
||||||
}
|
}
|
||||||
@@ -83,11 +71,7 @@ function buildItem(data: IFormData, status: string, employeeId: number, employee
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить обходной лист: содержимое + маршрут (согласование + исполнение).
|
* Сохранить обходной лист: содержимое + маршрут (согласование + исполнение).
|
||||||
@@ -111,23 +95,10 @@ export async function saveClearanceRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const employee = await ensureEmployee(data.Employee);
|
const employee = await ensureEmployee(data.Employee);
|
||||||
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(clearanceApprovalService(listId), result.id, approvers, executors, status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(clearanceApprovalService(listId), id, approvers, executors, status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,17 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
// Числовые поля: пустая строка → null, иначе Number().
|
// Числовые поля: пустая строка → null, иначе Number().
|
||||||
const NUMBER_FIELDS: (keyof IFormData)[] = ['PpeHeight', 'PpeShoeSize', 'SalaryProbation', 'SalaryAfterProbation'];
|
const NUMBER_FIELDS: (keyof IFormData)[] = ['PpeHeight', 'PpeShoeSize', 'SalaryProbation', 'SalaryAfterProbation'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function hireApprovalService(listId?: string): ApprovalListService {
|
export function hireApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Осмысленный заголовок элемента списка (системная колонка Title). */
|
/** Осмысленный заголовок элемента списка (системная колонка Title). */
|
||||||
@@ -42,11 +35,7 @@ function buildItem(data: IFormData, status: string): Record<string, unknown> {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку «на прием»: контент + маршрут (согласующие + исполнители) со статусом.
|
* Сохранить заявку «на прием»: контент + маршрут (согласующие + исполнители) со статусом.
|
||||||
@@ -72,22 +61,9 @@ export async function saveHireRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const item = buildItem(data, status);
|
const item = buildItem(data, status);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(hireApprovalService(listId), result.id, approvers, executors, status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(hireApprovalService(listId), id, approvers, executors, status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { getSP } from '../../shared/pnp/pnpjs';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
import { ISaveItemResult, saveRequestItem } from '../../shared/dataList';
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
// Поля-люди (один человек): логин → ensureUser → Id в колонку <Field>Id.
|
// Поля-люди (один человек): логин → ensureUser → Id в колонку <Field>Id.
|
||||||
@@ -12,17 +11,12 @@ const MULTI_PERSON_FIELDS: (keyof IFormData)[] = ['HiringDecisionMaker'];
|
|||||||
const NUMBER_FIELDS: (keyof IFormData)[] = ['OpenVacanciesCount', 'RateProbation', 'RateAfterProbation'];
|
const NUMBER_FIELDS: (keyof IFormData)[] = ['OpenVacanciesCount', 'RateProbation', 'RateAfterProbation'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function selectionApprovalService(listId?: string): ApprovalListService {
|
export function selectionApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Логин → числовой Id пользователя на текущем сайте. */
|
/** Логин → числовой Id пользователя на текущем сайте. */
|
||||||
@@ -86,11 +80,7 @@ async function applyPeople(item: Record<string, unknown>, data: IFormData): Prom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку «на подбор»: содержимое + маршрут согласования.
|
* Сохранить заявку «на подбор»: содержимое + маршрут согласования.
|
||||||
@@ -114,24 +104,11 @@ export async function saveSelectionRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const item = buildScalarBody(data);
|
const item = buildScalarBody(data);
|
||||||
item.RequestStatus = status;
|
item.RequestStatus = status;
|
||||||
await applyPeople(item, data);
|
await applyPeople(item, data);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(selectionApprovalService(listId), result.id, approvers, [], status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(selectionApprovalService(listId), id, approvers, [], status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, resolveDataList, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
// Префикс уникального кода заявки — буквенная метка «1С» вместо числового id
|
// Префикс уникального кода заявки — буквенная метка «1С» вместо числового id
|
||||||
@@ -10,17 +8,12 @@ import { FORM_ID, IFormData } from './model';
|
|||||||
export const TICKET1C_CODE_PREFIX = '1С';
|
export const TICKET1C_CODE_PREFIX = '1С';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function ticket1cApprovalService(listId?: string): ApprovalListService {
|
export function ticket1cApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Поля элемента списка данных из модели формы. TaskName пишется в системную колонку Title. */
|
/** Поля элемента списка данных из модели формы. TaskName пишется в системную колонку Title. */
|
||||||
@@ -36,11 +29,7 @@ function buildItem(data: IFormData, status: string): Record<string, unknown> {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку в отдел 1С: содержимое + маршрут согласования.
|
* Сохранить заявку в отдел 1С: содержимое + маршрут согласования.
|
||||||
@@ -63,24 +52,11 @@ export async function saveTicketRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const item = buildItem(data, status);
|
const item = buildItem(data, status);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, TICKET1C_CODE_PREFIX, item);
|
||||||
let code: string | undefined;
|
await writeRoute(ticket1cApprovalService(listId), result.id, approvers, [], status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(TICKET1C_CODE_PREFIX, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(ticket1cApprovalService(listId), id, approvers, [], status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,12 +65,12 @@ export async function saveTicketRequest(
|
|||||||
* решение согласующего применяется из нескольких вкладок/сессий одновременно.
|
* решение согласующего применяется из нескольких вкладок/сессий одновременно.
|
||||||
*/
|
*/
|
||||||
export async function getPlannerTaskId(id: number, listId?: string): Promise<string | undefined> {
|
export async function getPlannerTaskId(id: number, listId?: string): Promise<string | undefined> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
const list = resolveDataList(FORM_ID, listId);
|
||||||
const item = (await list.items.getById(id).select('PlannerTaskId')()) as { PlannerTaskId?: string };
|
const item = (await list.items.getById(id).select('PlannerTaskId')()) as { PlannerTaskId?: string };
|
||||||
return item.PlannerTaskId || undefined;
|
return item.PlannerTaskId || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function setPlannerTaskId(id: number, taskId: string, listId?: string): Promise<void> {
|
export async function setPlannerTaskId(id: number, taskId: string, listId?: string): Promise<void> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
const list = resolveDataList(FORM_ID, listId);
|
||||||
await list.items.getById(id).update({ PlannerTaskId: taskId });
|
await list.items.getById(id).update({ PlannerTaskId: taskId });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
|
||||||
import { ILineItem } from '../../shared/ui';
|
import { ILineItem } from '../../shared/ui';
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function tmcTransferApprovalService(listId?: string): ApprovalListService {
|
export function tmcTransferApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Осмысленный заголовок элемента (системная колонка Title). */
|
/** Осмысленный заголовок элемента (системная колонка Title). */
|
||||||
@@ -43,11 +36,7 @@ function buildItem(data: IFormData, status: string): Record<string, unknown> {
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку «СЗ на перемещение ТМЦ»: контент + маршрут (согласующие + исполнители).
|
* Сохранить заявку «СЗ на перемещение ТМЦ»: контент + маршрут (согласующие + исполнители).
|
||||||
@@ -69,22 +58,9 @@ export async function saveTmcTransferRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const item = buildItem(data, status);
|
const item = buildItem(data, status);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(tmcTransferApprovalService(listId), result.id, approvers, executors, status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(tmcTransferApprovalService(listId), id, approvers, executors, status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,15 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
import { ensureEmployee } from '../../shared/employee';
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function unpaidLeaveApprovalService(listId?: string): ApprovalListService {
|
export function unpaidLeaveApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
|
||||||
|
|
||||||
/** email / claims-логин → пользователь сайта (Id для Person-поля + Title для заголовка). */
|
|
||||||
async function ensureUser(login: string): Promise<{ Id: number; Title: string }> {
|
|
||||||
const full = login.indexOf('|') >= 0 ? login : `i:0#.f|membership|${login}`;
|
|
||||||
return getSP().web.ensureUser(full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pad2(n: number): string {
|
function pad2(n: number): string {
|
||||||
@@ -64,11 +52,7 @@ function buildItem(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку без содержания: содержимое + маршрут согласования.
|
* Сохранить заявку без содержания: содержимое + маршрут согласования.
|
||||||
@@ -89,25 +73,12 @@ export async function saveUnpaidLeaveRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
const employee = await ensureEmployee(data.Employee);
|
||||||
const employee = await ensureUser(data.Employee);
|
|
||||||
// Замещающий необязателен: резолвим только если выбран.
|
// Замещающий необязателен: резолвим только если выбран.
|
||||||
const substituteId = data.Substitute ? (await ensureUser(data.Substitute)).Id : undefined;
|
const substituteId = data.Substitute ? (await ensureEmployee(data.Substitute)).Id : undefined;
|
||||||
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee, substituteId);
|
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee, substituteId);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(unpaidLeaveApprovalService(listId), result.id, approvers, [], status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(unpaidLeaveApprovalService(listId), id, approvers, [], status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,15 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
import { ensureEmployee } from '../../shared/employee';
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function vacationApprovalService(listId?: string): ApprovalListService {
|
export function vacationApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
|
||||||
|
|
||||||
/** email / claims-логин → пользователь сайта (Id для Person-поля + Title для заголовка). */
|
|
||||||
async function ensureEmployee(login: string): Promise<{ Id: number; Title: string }> {
|
|
||||||
const full = login.indexOf('|') >= 0 ? login : `i:0#.f|membership|${login}`;
|
|
||||||
return getSP().web.ensureUser(full);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pad2(n: number): string {
|
function pad2(n: number): string {
|
||||||
@@ -55,11 +43,7 @@ function buildItem(data: IFormData, status: string, employeeId: number, employee
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку на отпуск: содержимое + маршрут согласования.
|
* Сохранить заявку на отпуск: содержимое + маршрут согласования.
|
||||||
@@ -83,23 +67,10 @@ export async function saveVacationRequest(
|
|||||||
status: string,
|
status: string,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const employee = await ensureEmployee(data.Employee);
|
const employee = await ensureEmployee(data.Employee);
|
||||||
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
const item = buildItem(data, status, employee.Id, employee.Title || data.Employee);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(vacationApprovalService(listId), result.id, approvers, [], status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(vacationApprovalService(listId), id, approvers, [], status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,14 @@
|
|||||||
import { getSP } from '../../shared/pnp/pnpjs';
|
import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval';
|
||||||
import { ApprovalListService, IApproverToWrite, writeRoute } from '../../shared/approval';
|
import { ISaveItemResult, resolveDataList, saveRequestItem } from '../../shared/dataList';
|
||||||
import { buildRequestUniqueCode } from '../../shared/requestCode';
|
|
||||||
import { approvalListTitle, approvalListTitleForListId, dataListTitle } from '../../shared/listTitles';
|
|
||||||
import { FORM_ID, IFormData } from './model';
|
import { FORM_ID, IFormData } from './model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Экземпляр сервиса списка согласования этой формы.
|
* Экземпляр сервиса списка согласования этой формы — тонкая обёртка над
|
||||||
*
|
* approvalServiceFor (см. shared/approval/approvalServiceFactory.ts), под
|
||||||
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
* именем формы для читаемости вызывающего кода.
|
||||||
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
|
||||||
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
|
||||||
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
|
||||||
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
|
||||||
* а не тихо откатится на текущую партицию.
|
|
||||||
*/
|
*/
|
||||||
export function workplaceApprovalService(listId?: string): ApprovalListService {
|
export function workplaceApprovalService(listId?: string): ApprovalListService {
|
||||||
return new ApprovalListService(listId ? approvalListTitleForListId(FORM_ID, listId) : approvalListTitle(FORM_ID));
|
return approvalServiceFor(FORM_ID, listId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +23,7 @@ export async function updateReviewFields(
|
|||||||
fields: { Software: string; AccessRights: string },
|
fields: { Software: string; AccessRights: string },
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
const list = resolveDataList(FORM_ID, listId);
|
||||||
await list.items.getById(id).update({
|
await list.items.getById(id).update({
|
||||||
Software: fields.Software === '' ? null : fields.Software,
|
Software: fields.Software === '' ? null : fields.Software,
|
||||||
AccessRights: fields.AccessRights === '' ? null : fields.AccessRights,
|
AccessRights: fields.AccessRights === '' ? null : fields.AccessRights,
|
||||||
@@ -62,11 +55,7 @@ function buildItem(data: IFormData, status: string, sourceHireId?: number): Reco
|
|||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISaveResult {
|
export type ISaveResult = ISaveItemResult;
|
||||||
id: number;
|
|
||||||
/** Задан только при создании новой заявки (существующий код не меняется). */
|
|
||||||
code?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохранить заявку «орг. рабочего места»: контент + маршрут (согласующие + исполнители).
|
* Сохранить заявку «орг. рабочего места»: контент + маршрут (согласующие + исполнители).
|
||||||
@@ -92,22 +81,9 @@ export async function saveWorkplaceRequest(
|
|||||||
sourceHireId?: number,
|
sourceHireId?: number,
|
||||||
listId?: string
|
listId?: string
|
||||||
): Promise<ISaveResult> {
|
): Promise<ISaveResult> {
|
||||||
const list = listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(FORM_ID));
|
|
||||||
const item = buildItem(data, status, sourceHireId);
|
const item = buildItem(data, status, sourceHireId);
|
||||||
|
|
||||||
let id: number;
|
const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item);
|
||||||
let code: string | undefined;
|
await writeRoute(workplaceApprovalService(listId), result.id, approvers, executors, status);
|
||||||
if (existingId) {
|
return result;
|
||||||
await list.items.getById(existingId).update(item);
|
|
||||||
id = existingId;
|
|
||||||
} else {
|
|
||||||
const added = await list.items.add(item);
|
|
||||||
id = (added as { Id: number }).Id;
|
|
||||||
// Код известен только после создания элемента (нужен его Id).
|
|
||||||
code = buildRequestUniqueCode(requestTypeId, id, new Date());
|
|
||||||
await list.items.getById(id).update({ RequestUniqueCode: code });
|
|
||||||
}
|
|
||||||
|
|
||||||
await writeRoute(workplaceApprovalService(listId), id, approvers, executors, status);
|
|
||||||
return { id, code };
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { RequestTypeId } from '../../models/types';
|
||||||
|
import { approvalListTitle, approvalListTitleForListId } from '../listTitles';
|
||||||
|
import { ApprovalListService } from './approvalList.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Экземпляр сервиса списка согласования формы.
|
||||||
|
*
|
||||||
|
* listId — партиция КОНКРЕТНОЙ заявки (см. shared/approval/listPartitions.ts).
|
||||||
|
* Не задан — текущая партиция, как раньше. Список согласования ищется только по
|
||||||
|
* имени (нет прямой ссылки на него, в отличие от списка данных), поэтому для
|
||||||
|
* архивной партиции имя приходится резолвить через реестр — если реестр не
|
||||||
|
* знает про такой listId (устаревшая ссылка), резолвер бросит понятную ошибку,
|
||||||
|
* а не тихо откатится на текущую партицию.
|
||||||
|
*
|
||||||
|
* Раньше каждая форма объявляла свою «xApprovalService» с телом-копией этой
|
||||||
|
* функции (8 одинаковых реализаций) — оставлены только тонкие обёртки под
|
||||||
|
* именем формы (см. submit.ts каждой формы), чтобы вызывающий код не терял
|
||||||
|
* читаемость («vacationApprovalService» вместо безликого параметра formId).
|
||||||
|
*/
|
||||||
|
export function approvalServiceFor(formId: RequestTypeId, listId?: string): ApprovalListService {
|
||||||
|
return new ApprovalListService(
|
||||||
|
listId ? approvalListTitleForListId(formId, listId) : approvalListTitle(formId)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -42,6 +42,7 @@ export { useRequestTypeId } from './useRequestTypeId';
|
|||||||
export type { IRequestTypeIdState } from './useRequestTypeId';
|
export type { IRequestTypeIdState } from './useRequestTypeId';
|
||||||
export { ApprovalListService } from './approvalList.service';
|
export { ApprovalListService } from './approvalList.service';
|
||||||
export type { IApproverToWrite } from './approvalList.service';
|
export type { IApproverToWrite } from './approvalList.service';
|
||||||
|
export { approvalServiceFor } from './approvalServiceFactory';
|
||||||
export { ApproverService } from './approverDecision.service';
|
export { ApproverService } from './approverDecision.service';
|
||||||
export type { ApproverDecision, IPendingRow } from './approverDecision.service';
|
export type { ApproverDecision, IPendingRow } from './approverDecision.service';
|
||||||
export { getPlannedMatrix, writeApprovers, writeRoute } from './approvalSubmission.service';
|
export { getPlannedMatrix, writeApprovers, writeRoute } from './approvalSubmission.service';
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import '@pnp/sp/webs';
|
||||||
|
import '@pnp/sp/lists';
|
||||||
|
import '@pnp/sp/items';
|
||||||
|
import { IList } from '@pnp/sp/lists';
|
||||||
|
import { getSP } from './pnp/pnpjs';
|
||||||
|
import { buildRequestUniqueCode } from './requestCode';
|
||||||
|
import { dataListTitle } from './listTitles';
|
||||||
|
import { RequestTypeId } from '../models/types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Список данных, в который фактически пишем: listId (конкретная партиция —
|
||||||
|
* либо ОБНОВЛЯЕМОЙ заявки, либо только что резолвленная текущая, см.
|
||||||
|
* getCurrentListPartition) или, если он не задан, список по конвенции имён
|
||||||
|
* (см. dataListTitle) — тот же откат, что действовал до партиционирования.
|
||||||
|
*
|
||||||
|
* Раньше эта строка (`listId ? getSP().web.getList(listId) : ...`) была
|
||||||
|
* скопирована в save/update-функции каждой формы и в submit.ts отдельных
|
||||||
|
* форм (Ticket1C — Planner, Clearance — updateApproverFields) — 8+ мест с
|
||||||
|
* одинаковым кодом. Расхождение здесь означало бы, что часть операций тихо
|
||||||
|
* пишет не в ту партицию.
|
||||||
|
*/
|
||||||
|
export function resolveDataList(formId: RequestTypeId, listId?: string): IList {
|
||||||
|
return listId ? getSP().web.getList(listId) : getSP().web.lists.getByTitle(dataListTitle(formId));
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ISaveItemResult {
|
||||||
|
id: number;
|
||||||
|
/** Задан только при создании новой заявки (существующий код не меняется). */
|
||||||
|
code?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Общее ядро сохранения элемента списка данных: резолв списка, создание/обновление,
|
||||||
|
* генерация уникального кода заявки. Вынесено из saveXRequest каждой формы — сам
|
||||||
|
* набор полей (buildItem) и работа с маршрутом (writeRoute) остаются у формы,
|
||||||
|
* форма отличается только ими.
|
||||||
|
*
|
||||||
|
* existingId задан → обновляем ту же запись, иначе создаём новую.
|
||||||
|
* codePrefix — обычно числовой RequestTypeId, но может быть строкой-меткой
|
||||||
|
* (см. buildRequestUniqueCode, TICKET1C_CODE_PREFIX).
|
||||||
|
*/
|
||||||
|
export async function saveRequestItem(
|
||||||
|
formId: RequestTypeId,
|
||||||
|
existingId: number | undefined,
|
||||||
|
listId: string | undefined,
|
||||||
|
codePrefix: number | string,
|
||||||
|
item: Record<string, unknown>
|
||||||
|
): Promise<ISaveItemResult> {
|
||||||
|
const list = resolveDataList(formId, listId);
|
||||||
|
|
||||||
|
if (existingId) {
|
||||||
|
await list.items.getById(existingId).update(item);
|
||||||
|
return { id: existingId };
|
||||||
|
}
|
||||||
|
|
||||||
|
const added = await list.items.add(item);
|
||||||
|
const id = (added as { Id: number }).Id;
|
||||||
|
// Код известен только после создания элемента (нужен его Id).
|
||||||
|
const code = buildRequestUniqueCode(codePrefix, id, new Date());
|
||||||
|
await list.items.getById(id).update({ RequestUniqueCode: code });
|
||||||
|
return { id, code };
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import '@pnp/sp/webs';
|
||||||
|
import '@pnp/sp/site-users/web';
|
||||||
|
import { getSP } from './pnp/pnpjs';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* email / claims-логин → пользователь сайта (Id для Person-поля + Title для заголовка).
|
||||||
|
* Было скопировано в submit.ts нескольких форм с сотрудником-инициатором
|
||||||
|
* (Vacation, Clearance) — вынесено сюда, чтобы не разойтись при правке.
|
||||||
|
*/
|
||||||
|
export async function ensureEmployee(login: string): Promise<{ Id: number; Title: string }> {
|
||||||
|
const full = login.indexOf('|') >= 0 ? login : `i:0#.f|membership|${login}`;
|
||||||
|
return getSP().web.ensureUser(full);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user