637e51d7f9
Tests / frontend-test (push) Successful in 1m24s
Co-authored-by: gorbenko.pavel <gorbenko.pavel@tansu.kz> Reviewed-on: http://git.tnsu.kz/timur.gorodetskiy/request-portal/pulls/23
71 lines
3.8 KiB
TypeScript
71 lines
3.8 KiB
TypeScript
import { AadHttpClient, HttpClientResponse } from '@microsoft/sp-http';
|
||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||
import { APPROVAL_API_CLIENT_ID, DICTIONARY_API_BASE_URL } from '../config';
|
||
import { IEmployeeOrganization } from './models/IEmployeeOrganization';
|
||
import { ICompany } from './models/ICompany';
|
||
|
||
// GET /Employee/ByEmail?Email=... — организации сотрудника (см. IEmployeeOrganization:
|
||
// один email может вернуть несколько записей). 404 (email не найден в системе
|
||
// кадров) — не ошибка формы, просто пусто: не у каждого приглашённого/внешнего
|
||
// пользователя портала есть карточка сотрудника.
|
||
async function fetchEmployeeOrganizations(context: WebPartContext, email: string): Promise<IEmployeeOrganization[]> {
|
||
const client = await context.aadHttpClientFactory.getClient(APPROVAL_API_CLIENT_ID);
|
||
const response: HttpClientResponse = await client.get(
|
||
`${DICTIONARY_API_BASE_URL}/Employee/ByEmail?Email=${encodeURIComponent(email)}`,
|
||
AadHttpClient.configurations.v1
|
||
);
|
||
if (response.status === 404) return [];
|
||
if (!response.ok) {
|
||
throw new Error(`Employee/ByEmail: ${response.status} ${response.statusText}`);
|
||
}
|
||
const body = (await response.json()) as Array<Record<string, unknown>>;
|
||
return body.map((r) => ({
|
||
id: (r.Id as string) || '',
|
||
fio: (r.Fio as string) || '',
|
||
email: (r.Email as string) || '',
|
||
iin: (r.Iin as string) || '',
|
||
company: (r.Company as string) || '',
|
||
companyId: (r.CompanyId as string) || '',
|
||
section: (r.Section as string) || '',
|
||
departmentId: (r.DepartmentId as string) || '',
|
||
position: (r.Position as string) || '',
|
||
mobile: (r.Mobile as string) || ''
|
||
}));
|
||
}
|
||
|
||
// Кеш по e-mail (не один общий промис, как у companies/departments — там список
|
||
// один на всех, здесь результат зависит от аргумента). Ошибку не кешируем — см.
|
||
// companies.service.ts, тот же принцип.
|
||
const cache = new Map<string, Promise<IEmployeeOrganization[]>>();
|
||
|
||
/** Организации сотрудника по e-mail. Пустой email → [] без обращения к API. */
|
||
export function getEmployeeOrganizations(context: WebPartContext, email: string): Promise<IEmployeeOrganization[]> {
|
||
if (!email) return Promise.resolve([]);
|
||
const cached = cache.get(email);
|
||
if (cached) return cached;
|
||
const promise = fetchEmployeeOrganizations(context, email).catch((e) => {
|
||
cache.delete(email);
|
||
throw e;
|
||
});
|
||
cache.set(email, promise);
|
||
return promise;
|
||
}
|
||
|
||
/**
|
||
* «Компания — должность» по каждой записи, по одной на строку (`\n`) — общий
|
||
* формат и для отображения (построчно), и для хранения в списке SharePoint
|
||
* (колонка Organization, Note — поддерживает переносы строк).
|
||
*/
|
||
export function formatEmployeeOrganizations(records: IEmployeeOrganization[]): string {
|
||
return records.map((r) => (r.position ? `${r.company} — ${r.position}` : r.company)).join('\n');
|
||
}
|
||
|
||
/**
|
||
* Организации сотрудника → значение для CompanyPickerMulti. companyId из
|
||
* Employee/ByEmail совпадает с Id в Dictionary/Companies (тот же источник),
|
||
* поэтому доп. запрос в справочник не нужен. Записи без компании пропускаем.
|
||
*/
|
||
export function employeeCompanies(records: IEmployeeOrganization[]): ICompany[] {
|
||
return records.filter((r) => r.companyId && r.company).map((r) => ({ Id: r.companyId, Name: r.company }));
|
||
}
|