Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
73 lines
2.3 KiB
TypeScript
73 lines
2.3 KiB
TypeScript
import {
|
|
fromPrice,
|
|
paramsSchemaSchema,
|
|
pricingSchema,
|
|
slotConfigSchema,
|
|
type CategoryCode,
|
|
type ParamsSchema,
|
|
type Pricing,
|
|
type SlotConfig,
|
|
} from '@barev/core';
|
|
import type { Db, Service, Tx } from '@barev/db';
|
|
import { DomainError } from './context.ts';
|
|
|
|
export interface ParsedService {
|
|
id: string;
|
|
code: string;
|
|
category: CategoryCode;
|
|
categoryDiscountPct: number;
|
|
flow: Service['flow'];
|
|
providerRole: Service['providerRole'];
|
|
pricing: Pricing;
|
|
paramsSchema: ParamsSchema;
|
|
slotConfig: SlotConfig;
|
|
lateCancelFeePct: number;
|
|
isOnline: boolean;
|
|
active: boolean;
|
|
fromPrice: number;
|
|
}
|
|
|
|
type ServiceWithCategory = Service & { category: { code: CategoryCode; barevPlusDiscountPct: number } };
|
|
|
|
export function parseService(s: ServiceWithCategory): ParsedService {
|
|
const pricing = pricingSchema.parse(s.pricing);
|
|
return {
|
|
id: s.id,
|
|
code: s.code,
|
|
category: s.category.code,
|
|
categoryDiscountPct: s.category.barevPlusDiscountPct,
|
|
flow: s.flow,
|
|
providerRole: s.providerRole,
|
|
pricing,
|
|
paramsSchema: paramsSchemaSchema.parse(s.paramsSchema),
|
|
slotConfig: slotConfigSchema.parse(s.slotConfig),
|
|
lateCancelFeePct: s.lateCancelFeePct,
|
|
isOnline: s.isOnline,
|
|
active: s.active,
|
|
fromPrice: fromPrice(pricing),
|
|
};
|
|
}
|
|
|
|
/** Каталог для лендинга и Mini App: все направления, у услуг — «от N ֏» и признак доступности */
|
|
export async function listCatalog(db: Db) {
|
|
const categories = await db.category.findMany({
|
|
orderBy: { sortOrder: 'asc' },
|
|
include: { services: { orderBy: { sortOrder: 'asc' }, include: { category: true } } },
|
|
});
|
|
return categories.map((c) => ({
|
|
code: c.code,
|
|
barevPlusDiscountPct: c.barevPlusDiscountPct,
|
|
services: c.services.map((s) => {
|
|
const p = parseService(s);
|
|
return { code: p.code, flow: p.flow, fromPrice: p.fromPrice, active: p.active, isOnline: p.isOnline };
|
|
}),
|
|
}));
|
|
}
|
|
|
|
export async function getServiceByCode(db: Db | Tx, code: string, opts: { activeOnly?: boolean } = {}): Promise<ParsedService> {
|
|
const s = await db.service.findUnique({ where: { code }, include: { category: true } });
|
|
if (!s) throw new DomainError('NOT_FOUND');
|
|
if (opts.activeOnly && !s.active) throw new DomainError('SERVICE_UNAVAILABLE');
|
|
return parseService(s);
|
|
}
|