base commit

This commit is contained in:
@kirill.komarov
2026-04-30 22:34:55 +05:00
parent 123d86091d
commit 9139a24093
46 changed files with 2023 additions and 153 deletions
+35 -12
View File
@@ -1,26 +1,49 @@
export const ORDER_STATUSES = [
'DRAFT',
'PENDING_PAYMENT',
'PAYMENT_VERIFICATION',
'PAID',
'IN_PROGRESS',
'SHIPPED',
'READY_FOR_PICKUP',
'DONE',
'CANCELLED',
]
export const ORDER_STATUS_TRANSITIONS = {
DRAFT: new Set(['PENDING_PAYMENT', 'CANCELLED']),
PENDING_PAYMENT: new Set(['PAID', 'CANCELLED']),
PAID: new Set(['IN_PROGRESS', 'CANCELLED']),
IN_PROGRESS: new Set(['SHIPPED', 'CANCELLED']),
SHIPPED: new Set(['DONE']),
DONE: new Set([]),
CANCELLED: new Set([]),
/**
* Переходы, которые делает админ через PATCH /api/admin/orders/:id/status
* (подтверждение получения пользователем — отдельный эндпоинт).
*/
export function canTransitionAdminOrderStatus(order, next) {
const from = order.status
const dt = order.deliveryType
if (from === next) return true
switch (from) {
case 'DRAFT':
return next === 'PENDING_PAYMENT' || next === 'CANCELLED'
case 'PENDING_PAYMENT':
return next === 'CANCELLED'
case 'PAYMENT_VERIFICATION':
return next === 'PAID' || next === 'CANCELLED'
case 'PAID':
return next === 'IN_PROGRESS' || next === 'CANCELLED'
case 'IN_PROGRESS':
if (next === 'CANCELLED') return true
if (dt === 'delivery') return next === 'SHIPPED'
if (dt === 'pickup') return next === 'READY_FOR_PICKUP'
return false
case 'SHIPPED':
case 'READY_FOR_PICKUP':
case 'DONE':
case 'CANCELLED':
return false
default:
return false
}
}
/** @deprecated используйте canTransitionAdminOrderStatus */
export function canTransitionOrderStatus(from, to) {
if (from === to) return true
const allowed = ORDER_STATUS_TRANSITIONS[from]
return Boolean(allowed?.has(to))
return canTransitionAdminOrderStatus({ status: from, deliveryType: 'delivery' }, to)
}
+13
View File
@@ -0,0 +1,13 @@
/** Публичное отображение автора отзыва (без «голого» email). */
export function publicReviewAuthorDisplay(user) {
if (!user || typeof user !== 'object') return 'Покупатель'
const name = typeof user.name === 'string' ? user.name.trim() : ''
if (name) return name
const email = typeof user.email === 'string' ? user.email.trim() : ''
const at = email.indexOf('@')
if (at <= 0) return 'Покупатель'
const local = email.slice(0, at)
const domain = email.slice(at + 1)
const masked = local.length <= 1 ? '*' : `${local.slice(0, 1)}***`
return `${masked}@${domain}`
}