Simplify order statuses and manager actions

This commit is contained in:
Ruslan Bakiev
2026-04-04 14:01:46 +07:00
parent 2f828cd164
commit 9017555722
6 changed files with 216 additions and 142 deletions

View File

@@ -65,25 +65,99 @@ function buildDates(createdAt: string | Date) {
};
}
export function getOrderStatusPresentation(status: string, createdAt: string | Date): StatusPresentation {
function buildManagerStages(status: string, createdAt: string | Date): StatusPresentation {
const dates = buildDates(createdAt);
if (status === 'CLIENT_REJECTED') {
const isOfferStage = ['WAITING_DOUBLE_CONFIRM', 'CONFIRMED'].includes(status);
const isWorkStage = ['IN_PROGRESS', 'COMPLETED'].includes(status);
const isStopped = ['CLIENT_REJECTED', 'MANAGER_REJECTED', 'MANAGER_BLOCKED'].includes(status);
const stages: TimelineStage[] = [
{
code: 'NEW',
label: 'Заявка',
note: 'Заказ создан и ждёт расчёта.',
dateLabel: formatDay(dates.created),
state: isOfferStage || isWorkStage || isStopped ? 'done' : 'current',
},
{
code: 'WAITING_DOUBLE_CONFIRM',
label: 'Предложение',
note: 'Цена и условия опубликованы клиенту.',
dateLabel: formatDay(dates.offer),
state: isWorkStage ? 'done' : isOfferStage ? 'current' : 'upcoming',
},
{
code: 'IN_PROGRESS',
label: status === 'COMPLETED' ? 'Исполнение завершено' : 'В работе',
note: status === 'COMPLETED'
? 'Заказ передан в работу и закрыт.'
: 'Заказ передан в производство или исполнение.',
dateLabel: formatDay(dates.production),
state: isWorkStage ? 'current' : 'upcoming',
},
];
if (status === 'MANAGER_BLOCKED') {
return {
title: 'Заказ остановлен клиентом',
summary: 'Согласование остановлено. Если нужно, заказ можно собрать заново с новыми условиями.',
title: 'Заказ на паузе',
summary: 'Нужно уточнение по заказу перед публикацией предложения.',
stages,
};
}
if (status === 'CLIENT_REJECTED' || status === 'MANAGER_REJECTED') {
return {
title: 'Заказ остановлен',
summary: 'Текущий заказ завершён без запуска в работу.',
stages,
};
}
if (isWorkStage) {
return {
title: status === 'COMPLETED' ? 'Заказ завершён' : 'Заказ в работе',
summary: status === 'COMPLETED'
? 'Исполнение завершено, история этапов сохранена.'
: 'Предложение согласовано, заказ уже в работе.',
stages,
};
}
if (isOfferStage) {
return {
title: 'Предложение отправлено',
summary: 'Клиент уже видит цену и условия. Следующий шаг для менеджера: пустить заказ в работу.',
stages,
};
}
return {
title: 'Ждём расчёт по заявке',
summary: 'Заполните цену по позициям и логистике, после этого предложение уйдёт клиенту автоматически.',
stages,
};
}
function buildClientStages(status: string, createdAt: string | Date): StatusPresentation {
const dates = buildDates(createdAt);
if (status === 'CLIENT_REJECTED' || status === 'MANAGER_REJECTED') {
return {
title: 'Заказ остановлен',
summary: 'Текущий заказ закрыт. При необходимости можно оформить новый заказ.',
stages: [
{
code: 'NEW',
label: 'Заявка принята',
note: 'Заказ попал в обработку.',
label: 'Заказ создан',
note: 'Заказ принят в обработку.',
dateLabel: formatDay(dates.created),
state: 'done',
},
{
code: 'CLIENT_REJECTED',
label: 'Клиент отказался от продолжения',
note: 'Текущий заказ закрыт без запуска в работу.',
code: status,
label: 'Заказ остановлен',
note: 'Дальнейшее исполнение не планируется.',
dateLabel: formatDay(dates.approval),
state: 'current',
},
@@ -91,26 +165,22 @@ export function getOrderStatusPresentation(status: string, createdAt: string | D
};
}
if (status === 'MANAGER_REJECTED' || status === 'MANAGER_BLOCKED') {
if (status === 'MANAGER_BLOCKED') {
return {
title: status === 'MANAGER_BLOCKED' ? 'Заказ ждёт уточнения' : 'Заказ остановлен менеджером',
summary: status === 'MANAGER_BLOCKED'
? 'Сейчас ждём уточнение параметров, после него заказ вернётся в работу.'
: 'Менеджер остановил обработку. При необходимости можно собрать новый заказ.',
title: 'Заказ ждёт уточнения',
summary: 'Менеджер уточняет параметры заказа перед расчётом.',
stages: [
{
code: 'NEW',
label: 'Заявка принята',
note: 'Заказ попал в обработку.',
label: 'Заказ создан',
note: 'Заказ принят в обработку.',
dateLabel: formatDay(dates.created),
state: 'done',
},
{
code: status,
label: status === 'MANAGER_BLOCKED' ? 'Нужно уточнение по заказу' : 'Обработка остановлена',
note: status === 'MANAGER_BLOCKED'
? 'Менеджер запросил уточнение перед продолжением.'
: 'Текущий заказ завершён без запуска в производство.',
label: 'Уточняем детали',
note: 'После уточнения покажем плановые даты по исполнению.',
dateLabel: formatDay(dates.approval),
state: 'current',
},
@@ -123,76 +193,62 @@ export function getOrderStatusPresentation(status: string, createdAt: string | D
const stages: TimelineStage[] = [
{
code: 'NEW',
label: 'Заявка принята',
note: олучили состав заказа и начали обработку.',
label: 'Заказ создан',
note: риняли заказ и начали обработку.',
dateLabel: formatDay(dates.created),
state: currentIndex > 0 ? 'done' : 'current',
},
{
code: 'MANAGER_PROCESSING',
label: 'Готовим предложение',
note: 'Уточняем цену, сроки и условия доставки.',
dateLabel: formatDay(dates.offer),
state: currentIndex > 1 ? 'done' : currentIndex === 1 ? 'current' : 'upcoming',
},
{
code: 'WAITING_DOUBLE_CONFIRM',
label: 'Ждём подтверждение',
note: 'Показываем согласованные условия и ждём финальное подтверждение.',
dateLabel: formatDay(dates.approval),
state: currentIndex > 2 ? 'done' : currentIndex === 2 ? 'current' : 'upcoming',
},
{
code: 'CONFIRMED',
label: 'Заказ подтверждён',
note: `Планируем передать в производство и ориентируемся на выпуск ${formatDay(dates.production)}.`,
label: 'Производство',
note: 'Плановая дата запуска или выхода из производства.',
dateLabel: formatDay(dates.production),
state: currentIndex > 3 ? 'done' : currentIndex === 3 ? 'current' : 'upcoming',
state: currentIndex > 3 ? 'done' : currentIndex >= 3 ? 'current' : 'upcoming',
},
{
code: 'IN_PROGRESS',
label: 'Заказ в работе',
note: `Сейчас идёт исполнение. Следующее ожидаемое обновление около ${formatDay(dates.shipment)}.`,
label: 'Отгрузка',
note: 'Плановая дата передачи в логистику.',
dateLabel: formatDay(dates.shipment),
state: currentIndex > 4 ? 'done' : currentIndex === 4 ? 'current' : 'upcoming',
state: currentIndex > 4 ? 'done' : currentIndex >= 4 ? 'current' : 'upcoming',
},
{
code: 'COMPLETED',
label: 'Заказ завершён',
note: 'Исполнение закрыто, заказ готов к выдаче или уже доставлен.',
label: 'Доставка',
note: 'Плановая дата получения заказа.',
dateLabel: formatDay(dates.delivered),
state: currentIndex === 5 ? 'current' : currentIndex > 5 ? 'done' : 'upcoming',
state: currentIndex >= 5 ? 'current' : 'upcoming',
},
];
if (status === 'NEW') {
return {
title: 'Собираем предложение по заказу',
summary: `Сейчас уточняем стоимость и комплектацию. Следующее обновление ориентировочно ${formatDay(dates.offer)}.`,
title: 'Заказ создан',
summary: 'Менеджер рассчитывает стоимость и готовит план по исполнению.',
stages,
};
}
if (status === 'MANAGER_PROCESSING') {
return {
title: 'Готовим условия по заказу',
summary: `Менеджер собирает финальные условия. Ориентир по следующему апдейту ${formatDay(dates.approval)}.`,
title: 'Готовим предложение',
summary: 'Собираем итоговые условия и скоро покажем плановые даты.',
stages,
};
}
if (status === 'WAITING_DOUBLE_CONFIRM') {
return {
title: 'Ожидаем подтверждение условий',
summary: 'Нужно подтвердить текущие условия, после этого сразу двинем заказ дальше.',
title: 'Предложение готово',
summary: 'Стоимость и условия уже рассчитаны. Следующий этап после запуска: производство.',
stages,
};
}
if (status === 'CONFIRMED') {
return {
title: 'Заказ подтверждён',
summary: `Ожидаем выпуск с производства ориентировочно ${formatDay(dates.production)}.`,
title: 'Планируем производство',
summary: `Ориентируемся на производство ${formatDay(dates.production)}, затем отгрузку и доставку по плану.`,
stages,
};
}
@@ -200,14 +256,24 @@ export function getOrderStatusPresentation(status: string, createdAt: string | D
if (status === 'IN_PROGRESS') {
return {
title: 'Заказ в работе',
summary: `Сейчас заказ исполняется. Следующее ожидаемое обновление около ${formatDay(dates.shipment)}.`,
summary: `Производство идёт. Следующая плановая дата: отгрузка около ${formatDay(dates.shipment)}.`,
stages,
};
}
return {
title: 'Заказ завершён',
summary: 'Работы по заказу завершены, история этапов сохранена ниже.',
title: 'Доставка по плану',
summary: `Финальный ориентир по заказу: доставка ${formatDay(dates.delivered)}.`,
stages,
};
}
export function getOrderStatusPresentation(
status: string,
createdAt: string | Date,
audience: 'client' | 'manager' = 'client',
): StatusPresentation {
return audience === 'manager'
? buildManagerStages(status, createdAt)
: buildClientStages(status, createdAt);
}