Monorepo skeleton, Prisma schema, core domain and services with tests
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
45d7512d2b
64 files changed
+9483
No files matched your search
@@ -0,0 +1,72 @@
|
||||
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);
|
||||
}
|
||||
Reference in new issue
Block a user