From c91d2dbc04a9b4812f487fe22713c98eef6798c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A2=D0=B8=D0=BC=D1=83=D1=80=20=D0=93=D0=BE=D1=80=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D1=86=D0=BA=D0=B8=D0=B9?= Date: Fri, 2 Oct 2026 09:34:51 +0500 Subject: [PATCH] =?UTF-8?q?fix:=20=D0=B4=D0=B0=D1=82=D0=B0=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=B4=D0=B0=D1=87=D0=B8=20=E2=80=94=20=D0=B4=D0=B5=D0=BD=D1=8C?= =?UTF-8?q?=20=D0=BE=D1=82=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B8,=20=D0=B0?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D1=81=D0=BE=D1=85=D1=80=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=87=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=D0=B8?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit В подборе и реферале черновик хранил дату первого сохранения, и через несколько дней заявка уходила на согласование со старой датой подачи. Теперь при отправке дата подачи всегда сегодняшняя, а открытый черновик сразу показывает сегодня (как уже было в объяснительной по СКУД). В реферале дату больше нельзя поправить руками. Общая логика — shared/submitDate. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../RecruitingSelectionForm.tsx | 3 +- .../forms/RecruitingSelection/submit.ts | 2 ++ .../forms/Referral/ReferralForm.tsx | 5 ++-- .../Referral/sections/ReferrerSection.tsx | 3 +- .../requestPortal/forms/Referral/submit.ts | 3 +- .../SkudExplanation/SkudExplanationForm.tsx | 6 ++-- .../forms/SkudExplanation/submit.ts | 3 +- .../requestPortal/shared/submitDate.test.ts | 21 +++++++++++++ .../requestPortal/shared/submitDate.ts | 30 +++++++++++++++++++ 9 files changed, 66 insertions(+), 10 deletions(-) create mode 100644 src/webparts/requestPortal/shared/submitDate.test.ts create mode 100644 src/webparts/requestPortal/shared/submitDate.ts diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx b/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx index b9e826d..08a0735 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx +++ b/src/webparts/requestPortal/forms/RecruitingSelection/RecruitingSelectionForm.tsx @@ -64,6 +64,7 @@ import { VacancySection } from './sections/VacancySection'; import { HealthTripsSection } from './sections/HealthTripsSection'; import { ConditionsSection } from './sections/ConditionsSection'; import { useStableCallback } from '../../shared/useStableCallback'; +import { submitDateOnOpen } from '../../shared/submitDate'; const RecruitingSelectionForm: React.FC = ({ requestType, @@ -105,7 +106,7 @@ const RecruitingSelectionForm: React.FC = ({ Promise.all([loadSelectionRequest(editId, editListId), getAttachments(editListId || dataListTitle(FORM_ID), editId)]) .then(([loaded, atts]) => { if (alive) { - setData(loaded.data); + setData({ ...loaded.data, SubmitDate: submitDateOnOpen(loaded.status, loaded.data.SubmitDate) }); setApproverChanges(loaded.approverChanges); setRequestStatus(loaded.status); setRequestCode(loaded.code || undefined); diff --git a/src/webparts/requestPortal/forms/RecruitingSelection/submit.ts b/src/webparts/requestPortal/forms/RecruitingSelection/submit.ts index 0faf9bf..526420c 100644 --- a/src/webparts/requestPortal/forms/RecruitingSelection/submit.ts +++ b/src/webparts/requestPortal/forms/RecruitingSelection/submit.ts @@ -3,6 +3,7 @@ import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } import { ISaveItemResult, resolveDataList, saveRequestItem } from '../../shared/dataList'; import { IFieldChange, serializeFieldChanges } from '../../shared/fieldChanges/fieldChanges'; import { buildRequestTitle } from '../../shared/requestTitle'; +import { submitDateOnSave } from '../../shared/submitDate'; import { FORM_ID, IFormData } from './model'; import { APPROVER_CHANGES_FIELD } from './changeTracking'; import { cleanVacancyReasons, legacyDetailsText } from './vacancyReasons'; @@ -146,6 +147,7 @@ export async function saveSelectionRequest( ): Promise { const item = buildScalarBody(data); item.RequestStatus = status; + item.SubmitDate = submitDateOnSave(status, data.SubmitDate) || null; await applyPeople(item, data); const result = await saveRequestItem(FORM_ID, existingId, listId, requestTypeId, item); diff --git a/src/webparts/requestPortal/forms/Referral/ReferralForm.tsx b/src/webparts/requestPortal/forms/Referral/ReferralForm.tsx index 9c55fe6..db7d1e0 100644 --- a/src/webparts/requestPortal/forms/Referral/ReferralForm.tsx +++ b/src/webparts/requestPortal/forms/Referral/ReferralForm.tsx @@ -59,6 +59,7 @@ import { VacancySection } from './sections/VacancySection'; import { CandidateInfoSection } from './sections/CandidateInfoSection'; import { AssessmentSection } from './sections/AssessmentSection'; import { useStableCallback } from '../../shared/useStableCallback'; +import { submitDateOnOpen } from '../../shared/submitDate'; const ReferralForm: React.FC = ({ requestType, @@ -111,7 +112,7 @@ const ReferralForm: React.FC = ({ Promise.all([loadReferralRequest(editId, editListId), getAttachments(editListId || dataListTitle(FORM_ID), editId)]) .then(([loaded, atts]) => { if (alive) { - setData(loaded.data); + setData({ ...loaded.data, SubmitDate: submitDateOnOpen(loaded.status, loaded.data.SubmitDate) }); setRequestStatus(loaded.status); setRequestCode(loaded.code || undefined); if (loaded.code) notifyCode(loaded.code); @@ -141,7 +142,7 @@ const ReferralForm: React.FC = ({ setData((prev) => ({ ...prev, Referrer: prev.Referrer || user.email, - SubmitDate: prev.SubmitDate || todayIso() + SubmitDate: todayIso() })); approval .getProfileFields(user.loginName) diff --git a/src/webparts/requestPortal/forms/Referral/sections/ReferrerSection.tsx b/src/webparts/requestPortal/forms/Referral/sections/ReferrerSection.tsx index 76715ad..7fd3ee9 100644 --- a/src/webparts/requestPortal/forms/Referral/sections/ReferrerSection.tsx +++ b/src/webparts/requestPortal/forms/Referral/sections/ReferrerSection.tsx @@ -5,8 +5,9 @@ import { ISectionProps, REFERRER_PLACEHOLDER } from '../model'; /** Секция 1: кто рекомендует — дата подачи, сам рекомендатель и его контакты. */ export const ReferrerSection: React.FC = ({ data, set, context, onReferrerChange, printOrgIndex }) => ( + {/* Дата подачи — всегда сегодняшняя (ставит форма, при отправке — заново), руками не меняется. */} - set('SubmitDate', v)} /> + set('SubmitDate', v)} readOnly /> = ({ loadSkudExplanationRequest(editId, editListId) .then((loaded) => { if (!alive) return; - // Черновик/доработку подают заново — дата подачи становится сегодняшней; - // у отправленной заявки остаётся та, с которой её подали. - const submitDate = isEditableStatus(loaded.status) ? todayDateKey() : loaded.data.SubmitDate; - setData({ ...loaded.data, SubmitDate: submitDate }); + setData({ ...loaded.data, SubmitDate: submitDateOnOpen(loaded.status, loaded.data.SubmitDate) }); setRequestStatus(loaded.status); setRequestCode(loaded.code || undefined); if (loaded.code) notifyCode(loaded.code); diff --git a/src/webparts/requestPortal/forms/SkudExplanation/submit.ts b/src/webparts/requestPortal/forms/SkudExplanation/submit.ts index d442630..0d41187 100644 --- a/src/webparts/requestPortal/forms/SkudExplanation/submit.ts +++ b/src/webparts/requestPortal/forms/SkudExplanation/submit.ts @@ -1,6 +1,7 @@ import { ApprovalListService, IApproverToWrite, approvalServiceFor, writeRoute } from '../../shared/approval'; import { ISaveItemResult, saveRequestItem } from '../../shared/dataList'; import { ensureEmployee } from '../../shared/employee'; +import { submitDateOnSave } from '../../shared/submitDate'; import { FORM_ID, IFormData, OTHER_REASON } from './model'; import { formatMissedDaysSummary, formatShortDate } from './noteText'; import { todayDateKey } from './skud/skudDays'; @@ -19,7 +20,7 @@ function buildItem(data: IFormData, status: string, employeeId: number, employee return { Title: buildTitle(employeeName), RequestStatus: status, - SubmitDate: data.SubmitDate || null, + SubmitDate: submitDateOnSave(status, data.SubmitDate) || null, EmployeeId: employeeId, SkudEmployeeFio: data.EmployeeFio || null, Position: data.Position || null, diff --git a/src/webparts/requestPortal/shared/submitDate.test.ts b/src/webparts/requestPortal/shared/submitDate.test.ts new file mode 100644 index 0000000..a546741 --- /dev/null +++ b/src/webparts/requestPortal/shared/submitDate.test.ts @@ -0,0 +1,21 @@ +import { REQUEST_STATUS } from './approval/models/statuses'; +import { submitDateOnOpen, submitDateOnSave, todaySubmitDate } from './submitDate'; + +const OLD_DATE = '2026-09-01'; + +describe('submitDate', () => { + it('отправка на согласование — сегодня, даже если черновик сохранён раньше', () => { + expect(submitDateOnSave(REQUEST_STATUS.onApproval, OLD_DATE)).toBe(todaySubmitDate()); + expect(submitDateOnSave(REQUEST_STATUS.queued, OLD_DATE)).toBe(todaySubmitDate()); + }); + + it('черновик хранит дату с экрана', () => { + expect(submitDateOnSave(REQUEST_STATUS.draft, OLD_DATE)).toBe(OLD_DATE); + }); + + it('открыли черновик или доработку — сегодня, отправленную — как подали', () => { + expect(submitDateOnOpen(REQUEST_STATUS.draft, OLD_DATE)).toBe(todaySubmitDate()); + expect(submitDateOnOpen(REQUEST_STATUS.returned, OLD_DATE)).toBe(todaySubmitDate()); + expect(submitDateOnOpen(REQUEST_STATUS.onApproval, OLD_DATE)).toBe(OLD_DATE); + }); +}); diff --git a/src/webparts/requestPortal/shared/submitDate.ts b/src/webparts/requestPortal/shared/submitDate.ts new file mode 100644 index 0000000..d870a3e --- /dev/null +++ b/src/webparts/requestPortal/shared/submitDate.ts @@ -0,0 +1,30 @@ +import { REQUEST_STATUS, isEditableStatus } from './approval/models/statuses'; + +function pad2(n: number): string { + return n < 10 ? `0${n}` : `${n}`; +} + +/** Сегодняшняя дата по местному времени, YYYY-MM-DD (формат input type=date). */ +export function todaySubmitDate(): string { + const now = new Date(); + return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())}`; +} + +/** + * «Дата подачи» для формы, открытой на редактирование. Черновик и доработку + * подают заново — на экране сегодняшняя дата, а не дата первого сохранения; + * у уже отправленной заявки остаётся та, с которой её подали. + */ +export function submitDateOnOpen(status: string, savedDate: string): string { + return isEditableStatus(status) ? todaySubmitDate() : savedDate; +} + +/** + * «Дата подачи» для записи в SharePoint из формы подачи. Любое сохранение кроме + * черновика — это отправка («На согласовании» или «Ждёт очереди», см. + * initialSubmitStatus): дата всегда сегодняшняя — форму могли открыть вчера, а + * черновик сохранить неделю назад. Черновик хранит то, что на экране. + */ +export function submitDateOnSave(status: string, currentDate: string): string { + return status === REQUEST_STATUS.draft ? currentDate : todaySubmitDate(); +}