@open-mercato/core 0.6.3-develop.3778.1.25fdb35f2e → 0.6.3-develop.3797.1.9d6338d7cd

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/modules/catalog/api/offers/route.js +1 -0
  2. package/dist/modules/catalog/api/offers/route.js.map +2 -2
  3. package/dist/modules/catalog/api/option-schemas/route.js +1 -0
  4. package/dist/modules/catalog/api/option-schemas/route.js.map +2 -2
  5. package/dist/modules/catalog/api/price-kinds/route.js +1 -0
  6. package/dist/modules/catalog/api/price-kinds/route.js.map +2 -2
  7. package/dist/modules/catalog/api/variants/route.js +1 -0
  8. package/dist/modules/catalog/api/variants/route.js.map +2 -2
  9. package/dist/modules/customers/api/people/route.js +1 -0
  10. package/dist/modules/customers/api/people/route.js.map +2 -2
  11. package/dist/modules/customers/api/tags/route.js +1 -0
  12. package/dist/modules/customers/api/tags/route.js.map +2 -2
  13. package/dist/modules/feature_toggles/api/global/route.js +1 -0
  14. package/dist/modules/feature_toggles/api/global/route.js.map +2 -2
  15. package/dist/modules/sales/api/adjustment-kinds/route.js +1 -0
  16. package/dist/modules/sales/api/adjustment-kinds/route.js.map +2 -2
  17. package/dist/modules/sales/api/channels/route.js +1 -0
  18. package/dist/modules/sales/api/channels/route.js.map +2 -2
  19. package/dist/modules/sales/api/delivery-windows/route.js +1 -0
  20. package/dist/modules/sales/api/delivery-windows/route.js.map +2 -2
  21. package/dist/modules/sales/api/document-addresses/route.js +1 -0
  22. package/dist/modules/sales/api/document-addresses/route.js.map +2 -2
  23. package/dist/modules/sales/api/payment-methods/route.js +1 -0
  24. package/dist/modules/sales/api/payment-methods/route.js.map +2 -2
  25. package/dist/modules/sales/api/price-kinds/route.js +1 -0
  26. package/dist/modules/sales/api/price-kinds/route.js.map +2 -2
  27. package/dist/modules/sales/api/quote-adjustments/route.js +1 -0
  28. package/dist/modules/sales/api/quote-adjustments/route.js.map +2 -2
  29. package/dist/modules/sales/api/shipping-methods/route.js +1 -0
  30. package/dist/modules/sales/api/shipping-methods/route.js.map +2 -2
  31. package/dist/modules/sales/api/tax-rates/route.js +1 -0
  32. package/dist/modules/sales/api/tax-rates/route.js.map +2 -2
  33. package/package.json +7 -7
  34. package/src/modules/catalog/api/offers/route.ts +1 -0
  35. package/src/modules/catalog/api/option-schemas/route.ts +1 -0
  36. package/src/modules/catalog/api/price-kinds/route.ts +1 -0
  37. package/src/modules/catalog/api/variants/route.ts +1 -0
  38. package/src/modules/customers/api/people/route.ts +1 -0
  39. package/src/modules/customers/api/tags/route.ts +1 -0
  40. package/src/modules/feature_toggles/api/global/route.ts +1 -0
  41. package/src/modules/sales/api/adjustment-kinds/route.ts +1 -0
  42. package/src/modules/sales/api/channels/route.ts +1 -0
  43. package/src/modules/sales/api/delivery-windows/route.ts +1 -0
  44. package/src/modules/sales/api/document-addresses/route.ts +1 -0
  45. package/src/modules/sales/api/payment-methods/route.ts +1 -0
  46. package/src/modules/sales/api/price-kinds/route.ts +1 -0
  47. package/src/modules/sales/api/quote-adjustments/route.ts +1 -0
  48. package/src/modules/sales/api/shipping-methods/route.ts +1 -0
  49. package/src/modules/sales/api/tax-rates/route.ts +1 -0
@@ -238,6 +238,7 @@ const crud = makeCrudRoute({
238
238
  tenantField: "tenantId",
239
239
  softDeleteField: "deletedAt"
240
240
  },
241
+ indexer: { entityType: E.catalog.catalog_offer },
241
242
  list: {
242
243
  schema: listSchema,
243
244
  entityId: E.catalog.catalog_offer,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/catalog/api/offers/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CatalogOffer, CatalogProduct, CatalogProductPrice, CatalogProductVariant } from '../../data/entities'\nimport { offerCreateSchema, offerUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/catalog_offer'\nimport { parseIdList } from '../products/route'\nimport { extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n productId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n channelIds: z.string().optional(),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n isActive: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype OfferListQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n POST: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport function normalizeSearch(term?: string | null): string | null {\n if (!term) return null\n const trimmed = term.trim()\n if (!trimmed.length) return null\n return trimmed\n}\n\nexport function buildOfferFilters(query: OfferListQuery): Record<string, unknown> {\n const filters: Record<string, unknown> = {}\n const searchTerm = normalizeSearch(query.search)\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n if (query.productId) {\n filters.product_id = { $eq: query.productId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n } else {\n const channelIds = parseIdList(query.channelIds)\n if (channelIds.length) {\n filters.channel_id = { $in: channelIds }\n }\n }\n if (searchTerm) {\n const like = `%${escapeLikePattern(searchTerm)}%`\n filters.$or = [{ [F.title]: { $ilike: like } }, { [F.description]: { $ilike: like } }]\n }\n const isActive = parseBooleanToken(query.isActive)\n if (isActive !== null) filters[F.is_active] = isActive\n return filters\n}\n\nexport async function decorateOffersWithDetails(\n items: Record<string, unknown>[],\n ctx: CrudCtx,\n): Promise<void> {\n if (!items.length) return\n const offerIds = items\n .map((item) => (item?.id ? String(item.id) : null))\n .filter((value): value is string => !!value)\n const productIds = items\n .map((item) => (item?.productId ? String(item.productId) : null))\n .filter((value): value is string => !!value)\n if (!offerIds.length && !productIds.length) return\n const em = ctx.container.resolve('em') as EntityManager\n const [products, prices, defaultVariants] = await Promise.all([\n productIds.length\n ? em.find(\n CatalogProduct,\n { id: { $in: productIds } },\n {\n fields: ['id', 'title', 'description', 'defaultMediaId', 'defaultMediaUrl', 'sku'],\n },\n )\n : [],\n offerIds.length\n ? findWithDecryption(\n em,\n CatalogProductPrice,\n { offer: { $in: offerIds } },\n { populate: ['priceKind'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n : [],\n productIds.length\n ? em.find(\n CatalogProductVariant,\n { product: { $in: productIds }, isDefault: true },\n { fields: ['id', 'product'] },\n )\n : [],\n ])\n const productMap = new Map(\n products.map((product) => [\n product.id,\n {\n id: product.id,\n title: product.title,\n defaultMediaId: product.defaultMediaId ?? null,\n defaultMediaUrl: product.defaultMediaUrl ?? null,\n sku: product.sku ?? null,\n },\n ]),\n )\n const priceMap = new Map<string, Array<Record<string, unknown>>>()\n prices.forEach((price) => {\n const offerRef = price.offer\n const offerId =\n typeof offerRef === 'string'\n ? offerRef\n : offerRef && typeof offerRef === 'object' && 'id' in offerRef\n ? (offerRef as { id?: string }).id ?? null\n : null\n if (!offerId) return\n const priceKind = price.priceKind\n const priceKindId =\n typeof priceKind === 'string'\n ? priceKind\n : priceKind && typeof priceKind === 'object'\n ? (priceKind as { id?: string }).id ?? null\n : null\n const priceKindCode =\n priceKind && typeof priceKind === 'object' && 'code' in priceKind\n ? (priceKind as { code?: string }).code ?? null\n : null\n const priceKindTitle =\n priceKind && typeof priceKind === 'object' && 'title' in priceKind\n ? (priceKind as { title?: string }).title ?? null\n : null\n const displayMode =\n priceKind && typeof priceKind === 'object' && 'displayMode' in priceKind\n ? (priceKind as { displayMode?: string }).displayMode ?? 'excluding-tax'\n : 'excluding-tax'\n const bucket = priceMap.get(offerId) ?? []\n bucket.push({\n id: price.id,\n priceKindId,\n priceKindCode,\n priceKindTitle,\n currencyCode: price.currencyCode ?? null,\n unitPriceNet: price.unitPriceNet ?? null,\n unitPriceGross: price.unitPriceGross ?? null,\n displayMode,\n minQuantity: price.minQuantity ?? null,\n maxQuantity: price.maxQuantity ?? null,\n })\n priceMap.set(offerId, bucket)\n })\n const variantToProductMap = new Map<string, string>()\n defaultVariants.forEach((variant) => {\n const variantId = typeof variant.id === 'string' ? variant.id : null\n const productRef =\n typeof variant.product === 'string'\n ? variant.product\n : variant.product && typeof variant.product === 'object' && 'id' in variant.product\n ? (variant.product as { id?: string }).id ?? null\n : null\n if (variantId && productRef) {\n variantToProductMap.set(variantId, productRef)\n }\n })\n const DEFAULT_CHANNEL_KEY = '__default__'\n type ProductFallbackPrice = { prices: Record<string, unknown>[]; priority: number }\n const productChannelPriceMap = new Map<string, Map<string, ProductFallbackPrice>>()\n const assignFallbackPrice = (productRef: string | null, channelRef: string | null, payload: Record<string, unknown>, priority: number) => {\n if (!productRef) return\n const bucket = productChannelPriceMap.get(productRef) ?? new Map()\n const effectiveChannel = channelRef ?? DEFAULT_CHANNEL_KEY\n const existing = bucket.get(effectiveChannel)\n if (existing && existing.priority > priority) return\n if (existing && existing.priority === priority) {\n bucket.set(effectiveChannel, { prices: [...existing.prices, payload], priority })\n productChannelPriceMap.set(productRef, bucket)\n return\n }\n bucket.set(effectiveChannel, { prices: [payload], priority })\n productChannelPriceMap.set(productRef, bucket)\n }\n const channelIds = Array.from(new Set(\n items\n .map((item) => {\n if (typeof item?.channelId === 'string') return item.channelId\n if (typeof item?.channel_id === 'string') return item.channel_id\n return null\n })\n .filter((value): value is string => !!value),\n ))\n const channelFilterValues = channelIds.length ? [...channelIds, null] : [null]\n const fallbackTargets: Array<Record<string, unknown>> = []\n if (productIds.length) fallbackTargets.push({ product: { $in: productIds } })\n const defaultVariantIds = Array.from(variantToProductMap.keys())\n if (defaultVariantIds.length) fallbackTargets.push({ variant: { $in: defaultVariantIds } })\n const fallbackEntries = fallbackTargets.length\n ? await findWithDecryption(\n em,\n CatalogProductPrice,\n {\n offer: null,\n $and: [\n { $or: fallbackTargets },\n channelFilterValues.includes(null)\n ? {\n $or: [\n { channelId: { $in: channelFilterValues.filter((id): id is string => typeof id === 'string') } },\n { channelId: null },\n ],\n }\n : { channelId: { $in: channelFilterValues } },\n ],\n },\n { populate: ['priceKind'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n : []\n fallbackEntries.forEach((entry) => {\n const entryChannelId = typeof entry.channelId === 'string' && entry.channelId.length\n ? entry.channelId\n : null\n const priceKind = entry.priceKind ?? null\n const priceKindId =\n typeof priceKind?.id === 'string'\n ? priceKind.id\n : null\n const priceKindCode =\n typeof priceKind?.code === 'string'\n ? priceKind.code\n : null\n const priceKindTitle =\n typeof priceKind?.title === 'string'\n ? priceKind.title\n : null\n const displayMode = typeof priceKind?.displayMode === 'string'\n ? priceKind.displayMode\n : typeof (priceKind as any)?.display_mode === 'string'\n ? (priceKind as any).display_mode\n : 'excluding-tax'\n const payload = {\n priceKindId,\n priceKindCode,\n priceKindTitle,\n currencyCode: entry.currencyCode ?? null,\n unitPriceNet: entry.unitPriceNet ?? null,\n unitPriceGross: entry.unitPriceGross ?? null,\n displayMode,\n }\n const variantRef =\n typeof entry.variant === 'string'\n ? entry.variant\n : entry.variant && typeof entry.variant === 'object' && 'id' in entry.variant\n ? (entry.variant as { id?: string }).id ?? null\n : null\n if (variantRef) {\n const variantProduct = variantToProductMap.get(variantRef)\n const productRef =\n variantProduct\n ?? (typeof entry.product === 'string'\n ? entry.product\n : entry.product && typeof entry.product === 'object' && 'id' in entry.product\n ? (entry.product as { id?: string }).id ?? null\n : null)\n const priority = entryChannelId ? 4 : 3\n assignFallbackPrice(productRef, entryChannelId, payload, priority)\n return\n }\n const productRef =\n typeof entry.product === 'string'\n ? entry.product\n : entry.product && typeof entry.product === 'object' && 'id' in entry.product\n ? (entry.product as { id?: string }).id ?? null\n : null\n const priority = entryChannelId ? 2 : 1\n assignFallbackPrice(productRef, entryChannelId, payload, priority)\n })\n items.forEach((item) => {\n const productId = String(item?.productId ?? '')\n item.product = productId ? productMap.get(productId) ?? null : null\n item.prices = priceMap.get(String(item?.id ?? '')) ?? []\n const rowChannelId = typeof item?.channelId === 'string'\n ? item.channelId\n : typeof item?.channel_id === 'string'\n ? item.channel_id\n : null\n const bucket = productChannelPriceMap.get(productId)\n const channelKey = rowChannelId ?? DEFAULT_CHANNEL_KEY\n const channelPrice = bucket?.get(channelKey) ?? null\n const defaultPrice = bucket?.get(DEFAULT_CHANNEL_KEY) ?? null\n const effectivePrice = channelPrice ?? defaultPrice ?? null\n item.productChannelPrice = effectivePrice?.prices?.[0] ?? null\n item.productDefaultPrices = effectivePrice?.prices ?? []\n })\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogOffer,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_offer,\n fields: [\n F.id,\n 'product_id',\n F.organization_id,\n F.tenant_id,\n F.channel_id,\n F.title,\n F.description,\n 'default_media_id',\n 'default_media_url',\n F.metadata,\n F.is_active,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n title: F.title,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => buildOfferFilters(query),\n transformItem: (item: Record<string, unknown>) => {\n if (!item) return item\n const cfEntries = extractAllCustomFieldEntries(item)\n const base = {\n id: item.id,\n productId: item.product_id ?? null,\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n channelId: item.channel_id ?? null,\n title: item.title ?? '',\n description: item.description ?? null,\n defaultMediaId: item.default_media_id ?? null,\n defaultMediaUrl: item.default_media_url ?? null,\n metadata: item.metadata ?? null,\n isActive: item.is_active ?? false,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n return Object.keys(cfEntries).length ? { ...base, ...cfEntries } : base\n },\n },\n actions: {\n create: {\n commandId: 'catalog.offers.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(offerCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.offerId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.offers.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(offerUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.offers.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) {\n throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Offer id is required.') })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload.items) ? payload.items : []\n if (!items.length) return\n await decorateOffersWithDetails(items, ctx)\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst offerListItemSchema = z.object({\n id: z.string().uuid(),\n productId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n channelId: z.string().uuid().nullable().optional(),\n title: z.string(),\n description: z.string().nullable().optional(),\n defaultMediaId: z.string().uuid().nullable().optional(),\n defaultMediaUrl: z.string().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n isActive: z.boolean().nullable().optional(),\n createdAt: z.string().nullable().optional(),\n updatedAt: z.string().nullable().optional(),\n product: z.record(z.string(), z.unknown()).nullable().optional(),\n prices: z.array(z.record(z.string(), z.unknown())).optional(),\n productChannelPrice: z.record(z.string(), z.unknown()).nullable().optional(),\n productDefaultPrices: z.array(z.record(z.string(), z.unknown())).optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Offer',\n pluralName: 'Offers',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(offerListItemSchema),\n create: {\n schema: offerCreateSchema,\n description: 'Creates a new offer linking a product to a sales channel.',\n },\n update: {\n schema: offerUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing offer by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an offer by id.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CatalogOffer, CatalogProduct, CatalogProductPrice, CatalogProductVariant } from '../../data/entities'\nimport { offerCreateSchema, offerUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/catalog_offer'\nimport { parseIdList } from '../products/route'\nimport { extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n productId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n channelIds: z.string().optional(),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n isActive: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype OfferListQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n POST: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['sales.channels.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport function normalizeSearch(term?: string | null): string | null {\n if (!term) return null\n const trimmed = term.trim()\n if (!trimmed.length) return null\n return trimmed\n}\n\nexport function buildOfferFilters(query: OfferListQuery): Record<string, unknown> {\n const filters: Record<string, unknown> = {}\n const searchTerm = normalizeSearch(query.search)\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n if (query.productId) {\n filters.product_id = { $eq: query.productId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n } else {\n const channelIds = parseIdList(query.channelIds)\n if (channelIds.length) {\n filters.channel_id = { $in: channelIds }\n }\n }\n if (searchTerm) {\n const like = `%${escapeLikePattern(searchTerm)}%`\n filters.$or = [{ [F.title]: { $ilike: like } }, { [F.description]: { $ilike: like } }]\n }\n const isActive = parseBooleanToken(query.isActive)\n if (isActive !== null) filters[F.is_active] = isActive\n return filters\n}\n\nexport async function decorateOffersWithDetails(\n items: Record<string, unknown>[],\n ctx: CrudCtx,\n): Promise<void> {\n if (!items.length) return\n const offerIds = items\n .map((item) => (item?.id ? String(item.id) : null))\n .filter((value): value is string => !!value)\n const productIds = items\n .map((item) => (item?.productId ? String(item.productId) : null))\n .filter((value): value is string => !!value)\n if (!offerIds.length && !productIds.length) return\n const em = ctx.container.resolve('em') as EntityManager\n const [products, prices, defaultVariants] = await Promise.all([\n productIds.length\n ? em.find(\n CatalogProduct,\n { id: { $in: productIds } },\n {\n fields: ['id', 'title', 'description', 'defaultMediaId', 'defaultMediaUrl', 'sku'],\n },\n )\n : [],\n offerIds.length\n ? findWithDecryption(\n em,\n CatalogProductPrice,\n { offer: { $in: offerIds } },\n { populate: ['priceKind'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n : [],\n productIds.length\n ? em.find(\n CatalogProductVariant,\n { product: { $in: productIds }, isDefault: true },\n { fields: ['id', 'product'] },\n )\n : [],\n ])\n const productMap = new Map(\n products.map((product) => [\n product.id,\n {\n id: product.id,\n title: product.title,\n defaultMediaId: product.defaultMediaId ?? null,\n defaultMediaUrl: product.defaultMediaUrl ?? null,\n sku: product.sku ?? null,\n },\n ]),\n )\n const priceMap = new Map<string, Array<Record<string, unknown>>>()\n prices.forEach((price) => {\n const offerRef = price.offer\n const offerId =\n typeof offerRef === 'string'\n ? offerRef\n : offerRef && typeof offerRef === 'object' && 'id' in offerRef\n ? (offerRef as { id?: string }).id ?? null\n : null\n if (!offerId) return\n const priceKind = price.priceKind\n const priceKindId =\n typeof priceKind === 'string'\n ? priceKind\n : priceKind && typeof priceKind === 'object'\n ? (priceKind as { id?: string }).id ?? null\n : null\n const priceKindCode =\n priceKind && typeof priceKind === 'object' && 'code' in priceKind\n ? (priceKind as { code?: string }).code ?? null\n : null\n const priceKindTitle =\n priceKind && typeof priceKind === 'object' && 'title' in priceKind\n ? (priceKind as { title?: string }).title ?? null\n : null\n const displayMode =\n priceKind && typeof priceKind === 'object' && 'displayMode' in priceKind\n ? (priceKind as { displayMode?: string }).displayMode ?? 'excluding-tax'\n : 'excluding-tax'\n const bucket = priceMap.get(offerId) ?? []\n bucket.push({\n id: price.id,\n priceKindId,\n priceKindCode,\n priceKindTitle,\n currencyCode: price.currencyCode ?? null,\n unitPriceNet: price.unitPriceNet ?? null,\n unitPriceGross: price.unitPriceGross ?? null,\n displayMode,\n minQuantity: price.minQuantity ?? null,\n maxQuantity: price.maxQuantity ?? null,\n })\n priceMap.set(offerId, bucket)\n })\n const variantToProductMap = new Map<string, string>()\n defaultVariants.forEach((variant) => {\n const variantId = typeof variant.id === 'string' ? variant.id : null\n const productRef =\n typeof variant.product === 'string'\n ? variant.product\n : variant.product && typeof variant.product === 'object' && 'id' in variant.product\n ? (variant.product as { id?: string }).id ?? null\n : null\n if (variantId && productRef) {\n variantToProductMap.set(variantId, productRef)\n }\n })\n const DEFAULT_CHANNEL_KEY = '__default__'\n type ProductFallbackPrice = { prices: Record<string, unknown>[]; priority: number }\n const productChannelPriceMap = new Map<string, Map<string, ProductFallbackPrice>>()\n const assignFallbackPrice = (productRef: string | null, channelRef: string | null, payload: Record<string, unknown>, priority: number) => {\n if (!productRef) return\n const bucket = productChannelPriceMap.get(productRef) ?? new Map()\n const effectiveChannel = channelRef ?? DEFAULT_CHANNEL_KEY\n const existing = bucket.get(effectiveChannel)\n if (existing && existing.priority > priority) return\n if (existing && existing.priority === priority) {\n bucket.set(effectiveChannel, { prices: [...existing.prices, payload], priority })\n productChannelPriceMap.set(productRef, bucket)\n return\n }\n bucket.set(effectiveChannel, { prices: [payload], priority })\n productChannelPriceMap.set(productRef, bucket)\n }\n const channelIds = Array.from(new Set(\n items\n .map((item) => {\n if (typeof item?.channelId === 'string') return item.channelId\n if (typeof item?.channel_id === 'string') return item.channel_id\n return null\n })\n .filter((value): value is string => !!value),\n ))\n const channelFilterValues = channelIds.length ? [...channelIds, null] : [null]\n const fallbackTargets: Array<Record<string, unknown>> = []\n if (productIds.length) fallbackTargets.push({ product: { $in: productIds } })\n const defaultVariantIds = Array.from(variantToProductMap.keys())\n if (defaultVariantIds.length) fallbackTargets.push({ variant: { $in: defaultVariantIds } })\n const fallbackEntries = fallbackTargets.length\n ? await findWithDecryption(\n em,\n CatalogProductPrice,\n {\n offer: null,\n $and: [\n { $or: fallbackTargets },\n channelFilterValues.includes(null)\n ? {\n $or: [\n { channelId: { $in: channelFilterValues.filter((id): id is string => typeof id === 'string') } },\n { channelId: null },\n ],\n }\n : { channelId: { $in: channelFilterValues } },\n ],\n },\n { populate: ['priceKind'] },\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n : []\n fallbackEntries.forEach((entry) => {\n const entryChannelId = typeof entry.channelId === 'string' && entry.channelId.length\n ? entry.channelId\n : null\n const priceKind = entry.priceKind ?? null\n const priceKindId =\n typeof priceKind?.id === 'string'\n ? priceKind.id\n : null\n const priceKindCode =\n typeof priceKind?.code === 'string'\n ? priceKind.code\n : null\n const priceKindTitle =\n typeof priceKind?.title === 'string'\n ? priceKind.title\n : null\n const displayMode = typeof priceKind?.displayMode === 'string'\n ? priceKind.displayMode\n : typeof (priceKind as any)?.display_mode === 'string'\n ? (priceKind as any).display_mode\n : 'excluding-tax'\n const payload = {\n priceKindId,\n priceKindCode,\n priceKindTitle,\n currencyCode: entry.currencyCode ?? null,\n unitPriceNet: entry.unitPriceNet ?? null,\n unitPriceGross: entry.unitPriceGross ?? null,\n displayMode,\n }\n const variantRef =\n typeof entry.variant === 'string'\n ? entry.variant\n : entry.variant && typeof entry.variant === 'object' && 'id' in entry.variant\n ? (entry.variant as { id?: string }).id ?? null\n : null\n if (variantRef) {\n const variantProduct = variantToProductMap.get(variantRef)\n const productRef =\n variantProduct\n ?? (typeof entry.product === 'string'\n ? entry.product\n : entry.product && typeof entry.product === 'object' && 'id' in entry.product\n ? (entry.product as { id?: string }).id ?? null\n : null)\n const priority = entryChannelId ? 4 : 3\n assignFallbackPrice(productRef, entryChannelId, payload, priority)\n return\n }\n const productRef =\n typeof entry.product === 'string'\n ? entry.product\n : entry.product && typeof entry.product === 'object' && 'id' in entry.product\n ? (entry.product as { id?: string }).id ?? null\n : null\n const priority = entryChannelId ? 2 : 1\n assignFallbackPrice(productRef, entryChannelId, payload, priority)\n })\n items.forEach((item) => {\n const productId = String(item?.productId ?? '')\n item.product = productId ? productMap.get(productId) ?? null : null\n item.prices = priceMap.get(String(item?.id ?? '')) ?? []\n const rowChannelId = typeof item?.channelId === 'string'\n ? item.channelId\n : typeof item?.channel_id === 'string'\n ? item.channel_id\n : null\n const bucket = productChannelPriceMap.get(productId)\n const channelKey = rowChannelId ?? DEFAULT_CHANNEL_KEY\n const channelPrice = bucket?.get(channelKey) ?? null\n const defaultPrice = bucket?.get(DEFAULT_CHANNEL_KEY) ?? null\n const effectivePrice = channelPrice ?? defaultPrice ?? null\n item.productChannelPrice = effectivePrice?.prices?.[0] ?? null\n item.productDefaultPrices = effectivePrice?.prices ?? []\n })\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogOffer,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.catalog.catalog_offer },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_offer,\n fields: [\n F.id,\n 'product_id',\n F.organization_id,\n F.tenant_id,\n F.channel_id,\n F.title,\n F.description,\n 'default_media_id',\n 'default_media_url',\n F.metadata,\n F.is_active,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n title: F.title,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => buildOfferFilters(query),\n transformItem: (item: Record<string, unknown>) => {\n if (!item) return item\n const cfEntries = extractAllCustomFieldEntries(item)\n const base = {\n id: item.id,\n productId: item.product_id ?? null,\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n channelId: item.channel_id ?? null,\n title: item.title ?? '',\n description: item.description ?? null,\n defaultMediaId: item.default_media_id ?? null,\n defaultMediaUrl: item.default_media_url ?? null,\n metadata: item.metadata ?? null,\n isActive: item.is_active ?? false,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n return Object.keys(cfEntries).length ? { ...base, ...cfEntries } : base\n },\n },\n actions: {\n create: {\n commandId: 'catalog.offers.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(offerCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.offerId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.offers.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(offerUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.offers.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) {\n throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Offer id is required.') })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload.items) ? payload.items : []\n if (!items.length) return\n await decorateOffersWithDetails(items, ctx)\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst offerListItemSchema = z.object({\n id: z.string().uuid(),\n productId: z.string().uuid().nullable().optional(),\n organizationId: z.string().uuid().nullable().optional(),\n tenantId: z.string().uuid().nullable().optional(),\n channelId: z.string().uuid().nullable().optional(),\n title: z.string(),\n description: z.string().nullable().optional(),\n defaultMediaId: z.string().uuid().nullable().optional(),\n defaultMediaUrl: z.string().nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n isActive: z.boolean().nullable().optional(),\n createdAt: z.string().nullable().optional(),\n updatedAt: z.string().nullable().optional(),\n product: z.record(z.string(), z.unknown()).nullable().optional(),\n prices: z.array(z.record(z.string(), z.unknown())).optional(),\n productChannelPrice: z.record(z.string(), z.unknown()).nullable().optional(),\n productDefaultPrices: z.array(z.record(z.string(), z.unknown())).optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Offer',\n pluralName: 'Offers',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(offerListItemSchema),\n create: {\n schema: offerCreateSchema,\n description: 'Creates a new offer linking a product to a sales channel.',\n },\n update: {\n schema: offerUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing offer by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an offer by id.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": ["productRef", "priority"]
7
7
  }
@@ -74,6 +74,7 @@ const crud = makeCrudRoute({
74
74
  tenantField: "tenantId",
75
75
  softDeleteField: "deletedAt"
76
76
  },
77
+ indexer: { entityType: E.catalog.catalog_option_schema_template },
77
78
  list: {
78
79
  schema: listSchema,
79
80
  entityId: E.catalog.catalog_option_schema_template,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/catalog/api/option-schemas/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { buildCustomFieldFiltersFromQuery } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CatalogOptionSchemaTemplate } from '../../data/entities'\nimport {\n optionSchemaTemplateCreateSchema,\n optionSchemaTemplateUpdateSchema,\n} from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as FO from '#generated/entities/catalog_option_schema_template'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n isActive: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype SchemaQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.view'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport async function buildOptionSchemaFilters(\n query: SchemaQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n const term = sanitizeSearchTerm(query.search)\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [\n { name: { $ilike: like } },\n { description: { $ilike: like } },\n ]\n }\n const active = parseBooleanFlag(query.isActive)\n if (active !== undefined) filters.is_active = active\n const tenantId = ctx.auth?.tenantId ?? null\n if (tenantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_option_schema_template],\n query,\n em,\n tenantId,\n })\n Object.assign(filters, cfFilters)\n } catch {\n // ignore custom field filter errors and fall back to base filters\n }\n }\n return filters\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogOptionSchemaTemplate,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_option_schema_template,\n fields: [\n FO.id,\n FO.name,\n FO.code,\n FO.description,\n FO.schema,\n FO.metadata,\n FO.is_active,\n FO.created_at,\n FO.updated_at,\n ],\n sortFieldMap: {\n name: FO.name,\n code: FO.code,\n createdAt: FO.created_at,\n updatedAt: FO.updated_at,\n },\n buildFilters: buildOptionSchemaFilters,\n },\n actions: {\n create: {\n commandId: 'catalog.optionSchemas.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(optionSchemaTemplateCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.schemaId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.optionSchemas.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(optionSchemaTemplateUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.optionSchemas.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) {\n throw new CrudHttpError(400, {\n error: translate('catalog.errors.id_required', 'Option schema id is required.'),\n })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const { GET, POST, PUT, DELETE } = crud\n\nconst optionSchemaListItemSchema = z.object({\n id: z.string().uuid(),\n name: z.string(),\n code: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n schema: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Option Schema',\n pluralName: 'Option Schemas',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(optionSchemaListItemSchema),\n create: {\n schema: optionSchemaTemplateCreateSchema,\n description: 'Creates a new option schema template for product configurations.',\n },\n update: {\n schema: optionSchemaTemplateUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing option schema by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an option schema by id.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { buildCustomFieldFiltersFromQuery } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CatalogOptionSchemaTemplate } from '../../data/entities'\nimport {\n optionSchemaTemplateCreateSchema,\n optionSchemaTemplateUpdateSchema,\n} from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as FO from '#generated/entities/catalog_option_schema_template'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n isActive: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype SchemaQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.view'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport async function buildOptionSchemaFilters(\n query: SchemaQuery,\n ctx: CrudCtx,\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n const term = sanitizeSearchTerm(query.search)\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [\n { name: { $ilike: like } },\n { description: { $ilike: like } },\n ]\n }\n const active = parseBooleanFlag(query.isActive)\n if (active !== undefined) filters.is_active = active\n const tenantId = ctx.auth?.tenantId ?? null\n if (tenantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_option_schema_template],\n query,\n em,\n tenantId,\n })\n Object.assign(filters, cfFilters)\n } catch {\n // ignore custom field filter errors and fall back to base filters\n }\n }\n return filters\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogOptionSchemaTemplate,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.catalog.catalog_option_schema_template },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_option_schema_template,\n fields: [\n FO.id,\n FO.name,\n FO.code,\n FO.description,\n FO.schema,\n FO.metadata,\n FO.is_active,\n FO.created_at,\n FO.updated_at,\n ],\n sortFieldMap: {\n name: FO.name,\n code: FO.code,\n createdAt: FO.created_at,\n updatedAt: FO.updated_at,\n },\n buildFilters: buildOptionSchemaFilters,\n },\n actions: {\n create: {\n commandId: 'catalog.optionSchemas.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(optionSchemaTemplateCreateSchema, raw ?? {}, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.schemaId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.optionSchemas.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(optionSchemaTemplateUpdateSchema, raw ?? {}, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.optionSchemas.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) {\n throw new CrudHttpError(400, {\n error: translate('catalog.errors.id_required', 'Option schema id is required.'),\n })\n }\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const { GET, POST, PUT, DELETE } = crud\n\nconst optionSchemaListItemSchema = z.object({\n id: z.string().uuid(),\n name: z.string(),\n code: z.string().nullable().optional(),\n description: z.string().nullable().optional(),\n schema: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Option Schema',\n pluralName: 'Option Schemas',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(optionSchemaListItemSchema),\n create: {\n schema: optionSchemaTemplateCreateSchema,\n description: 'Creates a new option schema template for product configurations.',\n },\n update: {\n schema: optionSchemaTemplateUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing option schema by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes an option schema by id.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -40,6 +40,7 @@ const crud = makeCrudRoute({
40
40
  tenantField: "tenantId",
41
41
  softDeleteField: "deletedAt"
42
42
  },
43
+ indexer: { entityType: E.catalog.catalog_price_kind },
43
44
  list: {
44
45
  schema: listSchema,
45
46
  entityId: E.catalog.catalog_price_kind,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/catalog/api/price-kinds/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CatalogPriceKind } from '../../data/entities'\nimport { priceKindCreateSchema, priceKindUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/catalog_price_kind'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n isPromotion: z.string().optional(),\n isActive: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogPriceKind,\n idField: 'id',\n orgField: null,\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_price_kind,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.code,\n F.title,\n F.display_mode,\n F.currency_code,\n F.is_promotion,\n F.is_active,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n code: F.code,\n title: F.title,\n displayMode: F.display_mode,\n currencyCode: F.currency_code,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n const term = sanitizeSearchTerm(query.search)\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [{ [F.code]: { $ilike: like } }, { [F.title]: { $ilike: like } }]\n }\n const isPromotion = parseBooleanFlag(query.isPromotion)\n if (isPromotion !== undefined) {\n filters[F.is_promotion] = isPromotion\n }\n const isActive = parseBooleanFlag(query.isActive)\n if (isActive !== undefined) {\n filters[F.is_active] = isActive\n }\n return filters\n },\n },\n actions: {\n create: {\n commandId: 'catalog.priceKinds.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(priceKindCreateSchema, raw ?? {}, ctx, translate, { requireOrganization: false })\n },\n response: ({ result }) => ({ id: result?.priceKindId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.priceKinds.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(priceKindUpdateSchema, raw ?? {}, ctx, translate, { requireOrganization: false })\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.priceKinds.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Price kind id is required.') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst priceKindListItemSchema = z.object({\n id: z.string().uuid(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n code: z.string(),\n title: z.string(),\n display_mode: z.string().nullable().optional(),\n currency_code: z.string().nullable().optional(),\n is_promotion: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Price Kind',\n pluralName: 'Price Kinds',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(priceKindListItemSchema),\n create: {\n schema: priceKindCreateSchema,\n description: 'Creates a new price kind for categorizing product prices.',\n },\n update: {\n schema: priceKindUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing price kind by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a price kind by id.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { CatalogPriceKind } from '../../data/entities'\nimport { priceKindCreateSchema, priceKindUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { E } from '#generated/entities.ids.generated'\nimport * as F from '#generated/entities/catalog_price_kind'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.settings.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n isPromotion: z.string().optional(),\n isActive: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogPriceKind,\n idField: 'id',\n orgField: null,\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.catalog.catalog_price_kind },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_price_kind,\n fields: [\n F.id,\n F.organization_id,\n F.tenant_id,\n F.code,\n F.title,\n F.display_mode,\n F.currency_code,\n F.is_promotion,\n F.is_active,\n F.created_at,\n F.updated_at,\n ],\n sortFieldMap: {\n code: F.code,\n title: F.title,\n displayMode: F.display_mode,\n currencyCode: F.currency_code,\n createdAt: F.created_at,\n updatedAt: F.updated_at,\n },\n buildFilters: async (query) => {\n const filters: Record<string, unknown> = {}\n const term = sanitizeSearchTerm(query.search)\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [{ [F.code]: { $ilike: like } }, { [F.title]: { $ilike: like } }]\n }\n const isPromotion = parseBooleanFlag(query.isPromotion)\n if (isPromotion !== undefined) {\n filters[F.is_promotion] = isPromotion\n }\n const isActive = parseBooleanFlag(query.isActive)\n if (isActive !== undefined) {\n filters[F.is_active] = isActive\n }\n return filters\n },\n },\n actions: {\n create: {\n commandId: 'catalog.priceKinds.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(priceKindCreateSchema, raw ?? {}, ctx, translate, { requireOrganization: false })\n },\n response: ({ result }) => ({ id: result?.priceKindId ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.priceKinds.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n return parseScopedCommandInput(priceKindUpdateSchema, raw ?? {}, ctx, translate, { requireOrganization: false })\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.priceKinds.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Price kind id is required.') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst priceKindListItemSchema = z.object({\n id: z.string().uuid(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n code: z.string(),\n title: z.string(),\n display_mode: z.string().nullable().optional(),\n currency_code: z.string().nullable().optional(),\n is_promotion: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Price Kind',\n pluralName: 'Price Kinds',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(priceKindListItemSchema),\n create: {\n schema: priceKindCreateSchema,\n description: 'Creates a new price kind for categorizing product prices.',\n },\n update: {\n schema: priceKindUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing price kind by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a price kind by id.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -88,6 +88,7 @@ const crud = makeCrudRoute({
88
88
  tenantField: "tenantId",
89
89
  softDeleteField: "deletedAt"
90
90
  },
91
+ indexer: { entityType: E.catalog.catalog_product_variant },
91
92
  list: {
92
93
  schema: listSchema,
93
94
  entityId: E.catalog.catalog_product_variant,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/catalog/api/variants/route.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CatalogProduct, CatalogProductVariant } from '../../data/entities'\nimport { variantCreateSchema, variantUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as FV from '#generated/entities/catalog_product_variant'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst SENTINEL_ID_VALUES = new Set(['', 'create', 'new', 'null', 'undefined'])\n\nexport function stripPlaceholderId(source: Record<string, unknown>): void {\n if (!Object.prototype.hasOwnProperty.call(source, 'id')) return\n const value = source.id\n if (value === undefined || value === null) {\n delete source.id\n return\n }\n if (typeof value === 'string') {\n const raw = value.trim()\n if (!raw || SENTINEL_ID_VALUES.has(raw.toLowerCase())) {\n delete source.id\n } else {\n source.id = raw\n }\n }\n}\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n productId: z.string().uuid().optional(),\n sku: z.string().optional(),\n isActive: z.string().optional(),\n isDefault: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype VariantQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.view'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport async function buildVariantFilters(\n query: VariantQuery\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n const term = sanitizeSearchTerm(query.search)\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [\n { name: { $ilike: like } },\n { sku: { $ilike: like } },\n { barcode: { $ilike: like } },\n ]\n }\n if (query.productId) {\n filters.product_id = { $eq: query.productId }\n }\n if (query.sku && query.sku.trim()) {\n filters.sku = { $eq: query.sku.trim() }\n }\n const isActive = parseBooleanFlag(query.isActive)\n if (isActive !== undefined) filters.is_active = isActive\n const isDefault = parseBooleanFlag(query.isDefault)\n if (isDefault !== undefined) filters.is_default = isDefault\n return filters\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogProductVariant,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_product_variant,\n fields: [\n FV.id,\n 'product_id',\n FV.name,\n FV.sku,\n FV.barcode,\n FV.status_entry_id,\n FV.is_default,\n FV.is_active,\n FV.weight_value,\n FV.weight_unit,\n 'tax_rate_id',\n 'tax_rate',\n FV.dimensions,\n FV.metadata,\n FV.option_values,\n 'custom_fieldset_code',\n 'default_media_id',\n 'default_media_url',\n FV.created_at,\n FV.updated_at,\n ],\n sortFieldMap: {\n name: FV.name,\n sku: FV.sku,\n createdAt: FV.created_at,\n updatedAt: FV.updated_at,\n },\n buildFilters: async (query, ctx) => {\n const filters = await buildVariantFilters(query)\n const tenantId = ctx.auth?.tenantId ?? null\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_product_variant],\n query,\n em,\n tenantId,\n })\n Object.assign(filters, cfFilters)\n } catch {\n // ignore\n }\n return filters\n },\n decorateCustomFields: { entityIds: [E.catalog.catalog_product_variant] },\n transformItem: (item: any) => {\n if (!item) return item\n const normalized = { ...item }\n const cfEntries = extractAllCustomFieldEntries(item)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) delete normalized[key]\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'catalog.variants.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const payload =\n raw && typeof raw === 'object'\n ? { ...(raw as Record<string, unknown>) }\n : ({} as Record<string, unknown>)\n stripPlaceholderId(payload)\n const productId = typeof payload.productId === 'string' ? payload.productId : null\n if (productId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const product = await em.findOne(\n CatalogProduct,\n { id: productId, deletedAt: null },\n { fields: ['id', 'organizationId', 'tenantId'] }\n )\n if (product) {\n payload.organizationId = product.organizationId\n payload.tenantId = product.tenantId\n }\n } catch {\n // Scope hints are best-effort; command will enforce access\n }\n }\n return parseScopedCommandInput(variantCreateSchema, payload, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.variantId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.variants.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const payload =\n raw && typeof raw === 'object'\n ? { ...(raw as Record<string, unknown>) }\n : ({} as Record<string, unknown>)\n stripPlaceholderId(payload)\n const variantId = typeof payload.id === 'string' ? payload.id : null\n if (variantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const variant = await em.findOne(\n CatalogProductVariant,\n { id: variantId, deletedAt: null },\n { fields: ['id', 'organizationId', 'tenantId'] }\n )\n if (variant) {\n payload.organizationId = variant.organizationId\n payload.tenantId = variant.tenantId\n }\n } catch {\n // Ignore prefetch failures; command layer validates access\n }\n }\n return parseScopedCommandInput(variantUpdateSchema, payload, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.variants.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Variant id is required.') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst variantListItemSchema = z.object({\n id: z.string().uuid(),\n product_id: z.string().uuid().nullable().optional(),\n name: z.string().nullable().optional(),\n sku: z.string().nullable().optional(),\n barcode: z.string().nullable().optional(),\n status_entry_id: z.string().uuid().nullable().optional(),\n is_default: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n weight_value: z.number().nullable().optional(),\n weight_unit: z.string().nullable().optional(),\n dimensions: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n option_values: z.record(z.string(), z.unknown()).nullable().optional(),\n custom_fieldset_code: z.string().nullable().optional(),\n default_media_id: z.string().uuid().nullable().optional(),\n default_media_url: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Variant',\n pluralName: 'Variants',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(variantListItemSchema),\n create: {\n schema: variantCreateSchema,\n description: 'Creates a new product variant.',\n },\n update: {\n schema: variantUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing variant by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a variant by id.',\n },\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CatalogProduct, CatalogProductVariant } from '../../data/entities'\nimport { variantCreateSchema, variantUpdateSchema } from '../../data/validators'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { E } from '#generated/entities.ids.generated'\nimport * as FV from '#generated/entities/catalog_product_variant'\nimport { parseBooleanFlag, sanitizeSearchTerm } from '../helpers'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport {\n createCatalogCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst SENTINEL_ID_VALUES = new Set(['', 'create', 'new', 'null', 'undefined'])\n\nexport function stripPlaceholderId(source: Record<string, unknown>): void {\n if (!Object.prototype.hasOwnProperty.call(source, 'id')) return\n const value = source.id\n if (value === undefined || value === null) {\n delete source.id\n return\n }\n if (typeof value === 'string') {\n const raw = value.trim()\n if (!raw || SENTINEL_ID_VALUES.has(raw.toLowerCase())) {\n delete source.id\n } else {\n source.id = raw\n }\n }\n}\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n id: z.string().uuid().optional(),\n search: z.string().optional(),\n productId: z.string().uuid().optional(),\n sku: z.string().optional(),\n isActive: z.string().optional(),\n isDefault: z.string().optional(),\n withDeleted: z.coerce.boolean().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n })\n .passthrough()\n\ntype VariantQuery = z.infer<typeof listSchema>\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['catalog.products.view'] },\n POST: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['catalog.variants.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nexport async function buildVariantFilters(\n query: VariantQuery\n): Promise<Record<string, unknown>> {\n const filters: Record<string, unknown> = {}\n const term = sanitizeSearchTerm(query.search)\n if (query.id) {\n filters.id = { $eq: query.id }\n }\n if (term) {\n const like = `%${escapeLikePattern(term)}%`\n filters.$or = [\n { name: { $ilike: like } },\n { sku: { $ilike: like } },\n { barcode: { $ilike: like } },\n ]\n }\n if (query.productId) {\n filters.product_id = { $eq: query.productId }\n }\n if (query.sku && query.sku.trim()) {\n filters.sku = { $eq: query.sku.trim() }\n }\n const isActive = parseBooleanFlag(query.isActive)\n if (isActive !== undefined) filters.is_active = isActive\n const isDefault = parseBooleanFlag(query.isDefault)\n if (isDefault !== undefined) filters.is_default = isDefault\n return filters\n}\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CatalogProductVariant,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: { entityType: E.catalog.catalog_product_variant },\n list: {\n schema: listSchema,\n entityId: E.catalog.catalog_product_variant,\n fields: [\n FV.id,\n 'product_id',\n FV.name,\n FV.sku,\n FV.barcode,\n FV.status_entry_id,\n FV.is_default,\n FV.is_active,\n FV.weight_value,\n FV.weight_unit,\n 'tax_rate_id',\n 'tax_rate',\n FV.dimensions,\n FV.metadata,\n FV.option_values,\n 'custom_fieldset_code',\n 'default_media_id',\n 'default_media_url',\n FV.created_at,\n FV.updated_at,\n ],\n sortFieldMap: {\n name: FV.name,\n sku: FV.sku,\n createdAt: FV.created_at,\n updatedAt: FV.updated_at,\n },\n buildFilters: async (query, ctx) => {\n const filters = await buildVariantFilters(query)\n const tenantId = ctx.auth?.tenantId ?? null\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.catalog.catalog_product_variant],\n query,\n em,\n tenantId,\n })\n Object.assign(filters, cfFilters)\n } catch {\n // ignore\n }\n return filters\n },\n decorateCustomFields: { entityIds: [E.catalog.catalog_product_variant] },\n transformItem: (item: any) => {\n if (!item) return item\n const normalized = { ...item }\n const cfEntries = extractAllCustomFieldEntries(item)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) delete normalized[key]\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'catalog.variants.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const payload =\n raw && typeof raw === 'object'\n ? { ...(raw as Record<string, unknown>) }\n : ({} as Record<string, unknown>)\n stripPlaceholderId(payload)\n const productId = typeof payload.productId === 'string' ? payload.productId : null\n if (productId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const product = await em.findOne(\n CatalogProduct,\n { id: productId, deletedAt: null },\n { fields: ['id', 'organizationId', 'tenantId'] }\n )\n if (product) {\n payload.organizationId = product.organizationId\n payload.tenantId = product.tenantId\n }\n } catch {\n // Scope hints are best-effort; command will enforce access\n }\n }\n return parseScopedCommandInput(variantCreateSchema, payload, ctx, translate)\n },\n response: ({ result }) => ({ id: result?.variantId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: 'catalog.variants.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const payload =\n raw && typeof raw === 'object'\n ? { ...(raw as Record<string, unknown>) }\n : ({} as Record<string, unknown>)\n stripPlaceholderId(payload)\n const variantId = typeof payload.id === 'string' ? payload.id : null\n if (variantId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const variant = await em.findOne(\n CatalogProductVariant,\n { id: variantId, deletedAt: null },\n { fields: ['id', 'organizationId', 'tenantId'] }\n )\n if (variant) {\n payload.organizationId = variant.organizationId\n payload.tenantId = variant.tenantId\n }\n } catch {\n // Ignore prefetch failures; command layer validates access\n }\n }\n return parseScopedCommandInput(variantUpdateSchema, payload, ctx, translate)\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'catalog.variants.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n if (!id) throw new CrudHttpError(400, { error: translate('catalog.errors.id_required', 'Variant id is required.') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n})\n\nexport const GET = crud.GET\nexport const POST = crud.POST\nexport const PUT = crud.PUT\nexport const DELETE = crud.DELETE\n\nconst variantListItemSchema = z.object({\n id: z.string().uuid(),\n product_id: z.string().uuid().nullable().optional(),\n name: z.string().nullable().optional(),\n sku: z.string().nullable().optional(),\n barcode: z.string().nullable().optional(),\n status_entry_id: z.string().uuid().nullable().optional(),\n is_default: z.boolean().nullable().optional(),\n is_active: z.boolean().nullable().optional(),\n weight_value: z.number().nullable().optional(),\n weight_unit: z.string().nullable().optional(),\n dimensions: z.record(z.string(), z.unknown()).nullable().optional(),\n metadata: z.record(z.string(), z.unknown()).nullable().optional(),\n option_values: z.record(z.string(), z.unknown()).nullable().optional(),\n custom_fieldset_code: z.string().nullable().optional(),\n default_media_id: z.string().uuid().nullable().optional(),\n default_media_url: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n updated_at: z.string().nullable().optional(),\n})\n\nexport const openApi = createCatalogCrudOpenApi({\n resourceName: 'Variant',\n pluralName: 'Variants',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(variantListItemSchema),\n create: {\n schema: variantCreateSchema,\n description: 'Creates a new product variant.',\n },\n update: {\n schema: variantUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates an existing variant by id.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a variant by id.',\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -74,6 +74,7 @@ const crud = makeCrudRoute({
74
74
  softDeleteField: "deletedAt"
75
75
  },
76
76
  enrichers: { entityId: "customers.person" },
77
+ indexer: { entityType: E.customers.customer_entity },
77
78
  list: {
78
79
  schema: listSchema,
79
80
  entityId: E.customers.customer_entity,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/api/people/route.ts"],
4
- "sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerDealPersonLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { personCreateSchema, personUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries, splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeProfilePayload } from './payload'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n id: z.string().uuid().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.person' },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = consumeAdvancedFilterState(query)\n const filters: Record<string, unknown> = { kind: { $eq: 'person' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_person_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n 'seniority',\n 'timezone',\n 'linked_in_url',\n 'twitter_url',\n ],\n mapToEntityIds: {\n table: 'customer_people',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = `%${escapeLikePattern(query.search)}%`\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: `${escapeLikePattern(emailStartsWith)}%` }\n } else if (emailContains) {\n filters.primary_email = { $ilike: `%${escapeLikePattern(emailContains)}%` }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedCompanyId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n { company: query.excludeLinkedCompanyId },\n 'customers.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n console.warn('[customers.people.list] exclusion lookup failed; falling back to base result set', err)\n }\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n {\n deal: query.excludeLinkedDealId,\n },\n { populate: ['person'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n console.warn('[customers.people.list] exclusion lookup failed; falling back to base result set', err)\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_person_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n console.warn('[customers.people.list] custom field filter resolution failed; falling back to base filters', err)\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.people.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = personCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n personId: result?.personId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.people.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = personUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'customers.people.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.person_required', 'Person id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (\n item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null\n ))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const entities = await findWithDecryption(\n em,\n CustomerEntity,\n {\n id: { $in: ids },\n deletedAt: null,\n kind: 'person',\n } as FilterQuery<CustomerEntity>,\n undefined,\n decryptionScope,\n )\n const entitiesById = new Map<string, CustomerEntity>()\n for (const entity of entities) {\n entitiesById.set(entity.id, entity)\n }\n\n const where: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n where.organizationId = ctx.selectedOrganizationId\n }\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n where as FilterQuery<CustomerPersonProfile>,\n { populate: ['entity', 'company'] },\n decryptionScope,\n )\n\n const profilesByEntityId = new Map<string, CustomerPersonProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const entity = typeof record.id === 'string' ? entitiesById.get(record.id) : undefined\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!entity && !profile) return item\n return {\n ...record,\n display_name: entity?.displayName ?? record.display_name ?? null,\n description: entity?.description ?? record.description ?? null,\n owner_user_id: entity?.ownerUserId ?? record.owner_user_id ?? null,\n primary_email: entity?.primaryEmail ?? record.primary_email ?? null,\n primary_phone: entity?.primaryPhone ?? record.primary_phone ?? null,\n status: entity?.status ?? record.status ?? null,\n lifecycle_stage: entity?.lifecycleStage ?? record.lifecycle_stage ?? null,\n source: entity?.source ?? record.source ?? null,\n next_interaction_at: entity?.nextInteractionAt ? entity.nextInteractionAt.toISOString() : record.next_interaction_at ?? null,\n next_interaction_name: entity?.nextInteractionName ?? record.next_interaction_name ?? null,\n next_interaction_ref_id: entity?.nextInteractionRefId ?? record.next_interaction_ref_id ?? null,\n next_interaction_icon: entity?.nextInteractionIcon ?? record.next_interaction_icon ?? null,\n next_interaction_color: entity?.nextInteractionColor ?? record.next_interaction_color ?? null,\n first_name: profile?.firstName ?? null,\n last_name: profile?.lastName ?? null,\n preferred_name: profile?.preferredName ?? null,\n job_title: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n seniority: profile?.seniority ?? null,\n timezone: profile?.timezone ?? null,\n linked_in_url: profile?.linkedInUrl ?? null,\n twitter_url: profile?.twitterUrl ?? null,\n company_entity_id:\n profile?.company && typeof profile.company === 'object'\n ? profile.company.id\n : profile?.company ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst personListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst personCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n personId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Person',\n pluralName: 'People',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(personListItemSchema),\n create: {\n schema: personCreateSchema,\n responseSchema: personCreateResponseSchema,\n description: 'Creates a person contact using scoped organization and tenant identifiers.',\n },\n update: {\n schema: personUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates contact details or custom fields for a person.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a person by id. Request body or query may provide the identifier.',\n errors: [\n {\n status: 422,\n description: 'Person has dependent records (e.g. linked deals); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('PERSON_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
5
- "mappings": "AACA,SAAS,SAAS;AAClB,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS;AAClB,SAAS,oBAAoB,0BAA0B;AACvD,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,kCAAkC,8BAA8B,+BAA+B;AACxG,SAAS,yBAAyB;AAClC,SAAS,yBAAyB;AAClC,SAAS,0BAA0B;AACnC,SAAS,4BAA4B,+BAA+B;AACpE;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OACK;AACP,SAAS,+BAA+B;AAExC,MAAM,gBAAgB,EAAE,OAAO,CAAC,CAAC,EAAE,YAAY;AAE/C,MAAM,aAAa,EAChB,OAAO;AAAA,EACN,MAAM,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC;AAAA,EACxC,UAAU,EAAE,OAAO,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAAA,EACtD,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3B,iBAAiB,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,eAAe,EAAE,OAAO,EAAE,SAAS;AAAA,EACnC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,gBAAgB,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,oBAAoB,EAAE,OAAO,EAAE,SAAS;AAAA,EACxC,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,WAAW,EAAE,OAAO,EAAE,SAAS;AAAA,EAC/B,SAAS,EAAE,KAAK,CAAC,OAAO,MAAM,CAAC,EAAE,SAAS;AAAA,EAC1C,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/B,QAAQ,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,aAAa,EAAE,OAAO,EAAE,SAAS;AAAA,EACjC,YAAY,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,wBAAwB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EACnD,qBAAqB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAClD,CAAC,EACA,YAAY;AAEf,MAAM,gBAAgB;AAAA,EACpB,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,uBAAuB,EAAE;AAAA,EACrE,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAAA,EACxE,KAAK,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAAA,EACvE,QAAQ,EAAE,aAAa,MAAM,iBAAiB,CAAC,yBAAyB,EAAE;AAC5E;AAEO,MAAM,WAAW;AAExB,MAAM,OAAO,cAAc;AAAA,EACzB,UAAU;AAAA,EACV,KAAK;AAAA,IACH,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,UAAU;AAAA,IACV,aAAa;AAAA,IACb,iBAAiB;AAAA,EACnB;AAAA,EACA,WAAW,EAAE,UAAU,mBAAmB;AAAA,EAC1C,MAAM;AAAA,IACJ,QAAQ;AAAA,IACR,UAAU,EAAE,UAAU;AAAA,IACtB,QAAQ;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,cAAc;AAAA,MACZ,MAAM;AAAA,MACN,WAAW;AAAA,MACX,WAAW;AAAA,IACb;AAAA,IACA,cAAc,OAAO,OAAO,QAAQ;AAClC,YAAM,qBAAqB,2BAA2B,KAAK;AAC3D,YAAM,UAAmC,EAAE,MAAM,EAAE,KAAK,SAAS,EAAE;AACnE,UAAI,MAAM,GAAI,SAAQ,KAAK,EAAE,KAAK,MAAM,GAAG;AAC3C,UAAI,MAAM,QAAQ;AAChB,cAAM,cAAc,MAChB,MAAM,iDAAiD;AAAA,UACrD;AAAA,UACA,OAAO,MAAM;AAAA,UACb,SAAS;AAAA,YACP;AAAA,cACE,YAAY,EAAE,UAAU;AAAA,cACxB,QAAQ;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,YACF;AAAA,YACA;AAAA,cACE,YAAY,EAAE,UAAU;AAAA,cACxB,QAAQ;AAAA,gBACN;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,cACF;AAAA,cACA,gBAAgB;AAAA,gBACd,OAAO;AAAA,gBACP,cAAc;AAAA,cAChB;AAAA,YACF;AAAA,UACF;AAAA,QACF,CAAC,IACD;AACJ,YAAI,gBAAgB,QAAQ,YAAY,SAAS,GAAG;AAClD,mCAAyB,SAAS,WAAW;AAAA,QAC/C,OAAO;AACL,gBAAM,gBAAgB,IAAI,kBAAkB,MAAM,MAAM,CAAC;AACzD,kBAAQ,MAAM;AAAA,YACZ,EAAE,cAAc,EAAE,QAAQ,cAAc,EAAE;AAAA,YAC1C,EAAE,eAAe,EAAE,QAAQ,cAAc,EAAE;AAAA,YAC3C,EAAE,eAAe,EAAE,QAAQ,cAAc,EAAE;AAAA,YAC3C,EAAE,aAAa,EAAE,QAAQ,cAAc,EAAE;AAAA,YACzC,EAAE,uBAAuB,EAAE,QAAQ,cAAc,EAAE;AAAA,UACrD;AAAA,QACF;AAAA,MACF;AACA,YAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,KAAK,EAAE,YAAY,IAAI;AACnF,YAAM,kBAAkB,OAAO,MAAM,oBAAoB,WAAW,MAAM,gBAAgB,KAAK,EAAE,YAAY,IAAI;AACjH,YAAM,gBAAgB,OAAO,MAAM,kBAAkB,WAAW,MAAM,cAAc,KAAK,EAAE,YAAY,IAAI;AAC3G,UAAI,OAAO;AACT,gBAAQ,gBAAgB,EAAE,KAAK,MAAM;AAAA,MACvC,WAAW,iBAAiB;AAC1B,gBAAQ,gBAAgB,EAAE,QAAQ,GAAG,kBAAkB,eAAe,CAAC,IAAI;AAAA,MAC7E,WAAW,eAAe;AACxB,gBAAQ,gBAAgB,EAAE,QAAQ,IAAI,kBAAkB,aAAa,CAAC,IAAI;AAAA,MAC5E;AACA,UAAI,MAAM,QAAQ;AAChB,gBAAQ,SAAS,EAAE,KAAK,MAAM,OAAO;AAAA,MACvC;AACA,UAAI,MAAM,gBAAgB;AACxB,gBAAQ,kBAAkB,EAAE,KAAK,MAAM,eAAe;AAAA,MACxD;AACA,UAAI,MAAM,QAAQ;AAChB,gBAAQ,SAAS,EAAE,KAAK,MAAM,OAAO;AAAA,MACvC;AACA,YAAM,YAAY,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AACpE,YAAM,SAAS,UACZ,MAAM,GAAG,EACT,IAAI,CAAC,UAAkB,MAAM,KAAK,CAAC,EACnC,OAAO,CAAC,UAAkB,MAAM,SAAS,CAAC;AAC7C,YAAM,cAAc,kBAAkB,MAAM,WAAW,MAAM;AAC7D,UAAI,aAAa;AACf,gBAAQ,KAAK,EAAE,KAAK,uCAAuC;AAAA,MAC7D,WAAW,OAAO,SAAS,GAAG;AAC5B,gBAAQ,wBAAwB,IAAI,EAAE,KAAK,OAAO;AAAA,MACpD;AACA,YAAM,cAAc,oBAAI,IAAY;AACpC,YAAM,gBAAgB,OAAO,MAAM,eAAe,WAAW,MAAM,aAAa;AAChF,oBACG,MAAM,GAAG,EACT,IAAI,CAAC,UAAkB,MAAM,KAAK,CAAC,EACnC,OAAO,CAAC,UAAkB,MAAM,SAAS,CAAC,EAC1C,QAAQ,CAAC,UAAkB,YAAY,IAAI,KAAK,CAAC;AACpD,UAAI,OAAO,MAAM,wBAAwB;AACvC,YAAI;AACF,gBAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,gBAAM,kBAAkB;AAAA,YACtB,UAAU,IAAI,MAAM,YAAY;AAAA,YAChC,gBAAgB,IAAI,0BAA0B,IAAI,MAAM,SAAS;AAAA,UACnE;AACA,gBAAM,YAAY,MAAM;AAAA,YACtB;AAAA,YACA,EAAE,SAAS,MAAM,uBAAuB;AAAA,YACxC;AAAA,UACF;AACA,gBAAM,QAAQ;AAAA,YACZ,MAAM;AAAA,cACJ;AAAA,cACA;AAAA,cACA;AAAA,cACA,EAAE,UAAU,CAAC,QAAQ,EAAE;AAAA,cACvB;AAAA,YACF;AAAA,UACF;AACA,gBAAM,QAAQ,CAAC,SAAS;AACtB,kBAAM,WAAW,KAAK,QAAQ;AAC9B,gBAAI,OAAO,aAAa,YAAY,SAAS,SAAS,EAAG,aAAY,IAAI,QAAQ;AAAA,UACnF,CAAC;AAAA,QACH,SAAS,KAAK;AACZ,kBAAQ,KAAK,oFAAoF,GAAG;AAAA,QACtG;AAAA,MACF;AACA,UAAI,OAAO,MAAM,qBAAqB;AACpC,YAAI;AACF,gBAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,gBAAM,kBAAkB;AAAA,YACtB,UAAU,IAAI,MAAM,YAAY;AAAA,YAChC,gBAAgB,IAAI,0BAA0B,IAAI,MAAM,SAAS;AAAA,UACnE;AACA,gBAAM,QAAQ,MAAM;AAAA,YAClB;AAAA,YACA;AAAA,YACA;AAAA,cACE,MAAM,MAAM;AAAA,YACd;AAAA,YACA,EAAE,UAAU,CAAC,QAAQ,EAAE;AAAA,YACvB;AAAA,UACF;AACA,gBAAM,QAAQ,CAAC,SAAS;AACtB,kBAAM,WAAW,KAAK,QAAQ;AAC9B,gBAAI,OAAO,aAAa,YAAY,SAAS,SAAS,EAAG,aAAY,IAAI,QAAQ;AAAA,UACnF,CAAC;AAAA,QACH,SAAS,KAAK;AACZ,kBAAQ,KAAK,oFAAoF,GAAG;AAAA,QACtG;AAAA,MACF;AACA,6BAAuB,SAAS,MAAM,KAAK,WAAW,CAAC;AACvD,YAAM,WAAW,kBAAkB,MAAM,QAAQ;AACjD,UAAI,CAAC,SAAS,CAAC,mBAAmB,CAAC,iBAAiB,aAAa,MAAM;AACrE,gBAAQ,gBAAgB,EAAE,SAAS,SAAS;AAAA,MAC9C;AACA,YAAM,WAAW,kBAAkB,MAAM,QAAQ;AACjD,UAAI,aAAa,MAAM;AACrB,gBAAQ,gBAAgB,EAAE,SAAS,SAAS;AAAA,MAC9C;AACA,YAAM,qBAAqB,kBAAkB,MAAM,kBAAkB;AACrE,UAAI,uBAAuB,MAAM;AAC/B,gBAAQ,sBAAsB,EAAE,SAAS,mBAAmB;AAAA,MAC9D;AACA,YAAM,eAAqC,CAAC;AAC5C,UAAI,MAAM,aAAa;AACrB,cAAM,OAAO,IAAI,KAAK,MAAM,WAAW;AACvC,YAAI,CAAC,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,cAAa,OAAO;AAAA,MACzD;AACA,UAAI,MAAM,WAAW;AACnB,cAAM,KAAK,IAAI,KAAK,MAAM,SAAS;AACnC,YAAI,CAAC,OAAO,MAAM,GAAG,QAAQ,CAAC,EAAG,cAAa,OAAO;AAAA,MACvD;AACA,UAAI,OAAO,KAAK,YAAY,EAAE,QAAQ;AACpC,gBAAQ,aAAa;AAAA,MACvB;AACA,UAAI,KAAK;AACP,YAAI;AACF,gBAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,gBAAM,YAAY,MAAM,iCAAiC;AAAA,YACvD,WAAW,CAAC,EAAE,UAAU,iBAAiB,EAAE,UAAU,uBAAuB;AAAA,YAC5E;AAAA,YACA;AAAA,YACA,UAAU,IAAI,MAAM,YAAY;AAAA,UAClC,CAAC;AACD,iBAAO,OAAO,SAAS,SAAS;AAAA,QAClC,SAAS,KAAK;AACZ,kBAAQ,KAAK,+FAA+F,GAAG;AAAA,QACjH;AAAA,MACF;AACA,UAAI,OAAO,oBAAoB;AAC7B,cAAM,kBAAkB,wBAAwB,EAAE,GAAG,QAAQ,GAAG,kBAAkB;AAClF,cAAM,aAAa,MAAM,qCAAqC;AAAA,UAC5D;AAAA,UACA,UAAU,EAAE,UAAU;AAAA,UACtB,SAAS;AAAA,UACT,oBAAoB;AAAA,YAClB;AAAA,cACE,UAAU,EAAE,UAAU;AAAA,cACtB,OAAO;AAAA,cACP,OAAO;AAAA,cACP,gBAAgB;AAAA,cAChB,MAAM,EAAE,WAAW,MAAM,SAAS,YAAY;AAAA,YAChD;AAAA,UACF;AAAA,UACA,OAAO;AAAA,YACL;AAAA,cACE,OAAO;AAAA,cACP,OAAO;AAAA,cACP,MAAM,EAAE,OAAO,KAAK;AAAA,cACpB,IAAI,EAAE,OAAO,YAAY;AAAA,cACzB,MAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF,CAAC;AACD,iCAAyB,SAAS,UAAU;AAAA,MAC9C;AACA,aAAO;AAAA,IACT;AAAA,IACA,oBAAoB;AAAA,MAClB;AAAA,QACE,UAAU,EAAE,UAAU;AAAA,QACtB,OAAO;AAAA,QACP,OAAO;AAAA,QACP,gBAAgB;AAAA,QAChB,MAAM,EAAE,WAAW,MAAM,SAAS,YAAY;AAAA,MAChD;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM,EAAE,OAAO,KAAK;AAAA,QACpB,IAAI,EAAE,OAAO,YAAY;AAAA,QACzB,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,eAAe,CAAC,SAAS;AACvB,UAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,YAAM,SAAS;AACf,YAAM,aAAsC,EAAE,GAAG,OAAO;AACxD,aAAO,WAAW;AAClB,YAAM,YAAY,6BAA6B,MAAM;AACrD,iBAAW,OAAO,OAAO,KAAK,UAAU,GAAG;AACzC,YAAI,IAAI,WAAW,KAAK,GAAG;AACzB,iBAAO,WAAW,GAAG;AAAA,QACvB;AAAA,MACF;AACA,aAAO,EAAE,GAAG,YAAY,GAAG,UAAU;AAAA,IACvC;AAAA,EACF;AAAA,EACA,SAAS;AAAA,IACP,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,cAAM,EAAE,MAAM,OAAO,IAAI,wBAAwB,MAAM;AACvD,cAAM,SAAS,mBAAmB,MAAM,IAAI;AAC5C,eAAO,OAAO,KAAK,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,cAAc,OAAO,IAAI;AAAA,MAC5E;AAAA,MACA,UAAU,CAAC,EAAE,OAAO,OAAO;AAAA,QACzB,IAAI,QAAQ,YAAY,QAAQ,MAAM;AAAA,QACtC,UAAU,QAAQ,YAAY;AAAA,MAChC;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,IACA,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,KAAK,IAAI,MAAM;AAChC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,SAAS,kBAAkB,OAAO,CAAC,GAAG,KAAK,SAAS;AAC1D,cAAM,aAAa,wBAAwB,QAAQ,SAAS;AAC5D,cAAM,EAAE,MAAM,OAAO,IAAI,wBAAwB,UAAU;AAC3D,cAAM,SAAS,mBAAmB,MAAM,IAAI;AAC5C,eAAO,OAAO,KAAK,MAAM,EAAE,SAAS,EAAE,GAAG,QAAQ,cAAc,OAAO,IAAI;AAAA,MAC5E;AAAA,MACA,UAAU,OAAO,EAAE,IAAI,KAAK;AAAA,IAC9B;AAAA,IACA,QAAQ;AAAA,MACN,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,UAAU,OAAO,EAAE,QAAQ,IAAI,MAAM;AACnC,cAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,cAAM,KACJ,QAAQ,MAAM,MACd,QAAQ,MACR,QAAQ,OAAO,OACd,IAAI,UAAU,IAAI,IAAI,IAAI,QAAQ,GAAG,EAAE,aAAa,IAAI,IAAI,IAAI;AACnE,YAAI,CAAC,GAAI,OAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,oCAAoC,uBAAuB,EAAE,CAAC;AACvH,eAAO,EAAE,GAAG;AAAA,MACd;AAAA,MACA,UAAU,OAAO,EAAE,IAAI,KAAK;AAAA,IAC9B;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,WAAW,OAAO,SAAS,QAAQ;AACjC,YAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC/D,YAAM,MAAM,MACT,IAAI,CAAC,SACJ,QAAQ,OAAO,SAAS,YAAY,OAAQ,KAAiC,OAAO,WAC/E,KAAiC,KAClC,IACL,EACA,OAAO,CAAC,OAAoC,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC;AACtF,UAAI,CAAC,IAAI,OAAQ;AAEjB,YAAM,KAAK,IAAI,UAAU,QAAQ,IAAI;AACrC,YAAM,kBAAkB;AAAA,QACtB,UAAU,IAAI,MAAM,YAAY;AAAA,QAChC,gBAAgB,IAAI,0BAA0B,IAAI,MAAM,SAAS;AAAA,MACnE;AACA,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,UACE,IAAI,EAAE,KAAK,IAAI;AAAA,UACf,WAAW;AAAA,UACX,MAAM;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,eAAe,oBAAI,IAA4B;AACrD,iBAAW,UAAU,UAAU;AAC7B,qBAAa,IAAI,OAAO,IAAI,MAAM;AAAA,MACpC;AAEA,YAAM,QAAiC;AAAA,QACrC,QAAQ,EAAE,KAAK,IAAI;AAAA,QACnB,UAAU,IAAI,MAAM,YAAY;AAAA,MAClC;AACA,UAAI,IAAI,wBAAwB;AAC9B,cAAM,iBAAiB,IAAI;AAAA,MAC7B;AAEA,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,QACA,EAAE,UAAU,CAAC,UAAU,SAAS,EAAE;AAAA,QAClC;AAAA,MACF;AAEA,YAAM,qBAAqB,oBAAI,IAAmC;AAClE,iBAAW,WAAW,UAAU;AAC9B,cAAM,gBAAiB,QAA0C;AACjE,cAAM,WAAW,OAAO,eAAe,OAAO,WAAW,cAAc,KAAK;AAC5E,YAAI,SAAU,oBAAmB,IAAI,UAAU,OAAO;AAAA,MACxD;AAEA,cAAQ,QAAQ,MAAM,IAAI,CAAC,SAAkB;AAC3C,YAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,cAAM,SAAS;AACf,cAAM,SAAS,OAAO,OAAO,OAAO,WAAW,aAAa,IAAI,OAAO,EAAE,IAAI;AAC7E,cAAM,UAAU,OAAO,OAAO,OAAO,WAAW,mBAAmB,IAAI,OAAO,EAAE,IAAI;AACpF,YAAI,CAAC,UAAU,CAAC,QAAS,QAAO;AAChC,eAAO;AAAA,UACL,GAAG;AAAA,UACH,cAAc,QAAQ,eAAe,OAAO,gBAAgB;AAAA,UAC5D,aAAa,QAAQ,eAAe,OAAO,eAAe;AAAA,UAC1D,eAAe,QAAQ,eAAe,OAAO,iBAAiB;AAAA,UAC9D,eAAe,QAAQ,gBAAgB,OAAO,iBAAiB;AAAA,UAC/D,eAAe,QAAQ,gBAAgB,OAAO,iBAAiB;AAAA,UAC/D,QAAQ,QAAQ,UAAU,OAAO,UAAU;AAAA,UAC3C,iBAAiB,QAAQ,kBAAkB,OAAO,mBAAmB;AAAA,UACrE,QAAQ,QAAQ,UAAU,OAAO,UAAU;AAAA,UAC3C,qBAAqB,QAAQ,oBAAoB,OAAO,kBAAkB,YAAY,IAAI,OAAO,uBAAuB;AAAA,UACxH,uBAAuB,QAAQ,uBAAuB,OAAO,yBAAyB;AAAA,UACtF,yBAAyB,QAAQ,wBAAwB,OAAO,2BAA2B;AAAA,UAC3F,uBAAuB,QAAQ,uBAAuB,OAAO,yBAAyB;AAAA,UACtF,wBAAwB,QAAQ,wBAAwB,OAAO,0BAA0B;AAAA,UACzF,YAAY,SAAS,aAAa;AAAA,UAClC,WAAW,SAAS,YAAY;AAAA,UAChC,gBAAgB,SAAS,iBAAiB;AAAA,UAC1C,WAAW,SAAS,YAAY;AAAA,UAChC,YAAY,SAAS,cAAc;AAAA,UACnC,WAAW,SAAS,aAAa;AAAA,UACjC,UAAU,SAAS,YAAY;AAAA,UAC/B,eAAe,SAAS,eAAe;AAAA,UACvC,aAAa,SAAS,cAAc;AAAA,UACpC,mBACE,SAAS,WAAW,OAAO,QAAQ,YAAY,WAC3C,QAAQ,QAAQ,KAChB,SAAS,WAAW;AAAA,QAC5B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF,CAAC;AAED,MAAM,EAAE,MAAM,KAAK,OAAO,IAAI;AAGvB,MAAM,MAAM,KAAK;AAExB,MAAM,uBAAuB,EAAE,OAAO;AAAA,EACpC,IAAI,EAAE,OAAO,EAAE,KAAK;AAAA,EACpB,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,EAClC,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC5C,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACrD,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC9C,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAC9C,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACvC,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAChD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACvC,qBAAqB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACpD,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,yBAAyB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACxD,uBAAuB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACtD,wBAAwB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EACvD,iBAAiB,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACvD,WAAW,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS;AAAA,EACjD,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAC7C,CAAC;AAED,MAAM,6BAA6B,EAAE,OAAO;AAAA,EAC1C,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AAAA,EAC/B,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS;AACvC,CAAC;AAEM,MAAM,UAAU,2BAA2B;AAAA,EAChD,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,oBAAoB,8BAA8B,oBAAoB;AAAA,EACtE,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf;AAAA,EACA,QAAQ;AAAA,IACN,QAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,aAAa;AAAA,EACf;AAAA,EACA,KAAK;AAAA,IACH,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAAA,IAC1C,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,QACE,QAAQ;AAAA,QACR,aAAa;AAAA,QACb,QAAQ,EAAE,OAAO;AAAA,UACf,OAAO,EAAE,OAAO;AAAA,UAChB,MAAM,EAAE,QAAQ,uBAAuB;AAAA,QACzC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF,CAAC;",
4
+ "sourcesContent": ["import type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport { z } from 'zod'\nimport { makeCrudRoute } from '@open-mercato/shared/lib/crud/factory'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n CustomerDealPersonLink,\n CustomerEntity,\n CustomerPersonCompanyLink,\n CustomerPersonProfile,\n} from '../../data/entities'\nimport { E } from '#generated/entities.ids.generated'\nimport { personCreateSchema, personUpdateSchema } from '../../data/validators'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n applyEntityIdExclusion,\n applyEntityIdRestriction,\n findMatchingEntityIdsWithQueryEngine,\n findMatchingEntityIdsBySearchTokensAcrossSources,\n withScopedPayload,\n} from '../utils'\nimport { buildCustomFieldFiltersFromQuery, extractAllCustomFieldEntries, splitCustomFieldPayload } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { consumeAdvancedFilterState, mergeAdvancedFilterTree } from '@open-mercato/shared/lib/crud/advanced-filter-integration'\nimport {\n createCustomersCrudOpenApi,\n createPagedListResponseSchema,\n defaultOkResponseSchema,\n} from '../openapi'\nimport {\n filterActivePersonCompanyLinks,\n withActiveCustomerPersonCompanyLinkFilter,\n} from '../../lib/personCompanyLinkTable'\nimport { normalizeProfilePayload } from './payload'\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n email: z.string().optional(),\n emailStartsWith: z.string().optional(),\n emailContains: z.string().optional(),\n status: z.string().optional(),\n lifecycleStage: z.string().optional(),\n source: z.string().optional(),\n hasEmail: z.string().optional(),\n hasPhone: z.string().optional(),\n hasNextInteraction: z.string().optional(),\n createdFrom: z.string().optional(),\n createdTo: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n id: z.string().uuid().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n excludeIds: z.string().optional(),\n excludeLinkedCompanyId: z.string().uuid().optional(),\n excludeLinkedDealId: z.string().uuid().optional(),\n })\n .passthrough()\n\nconst routeMetadata = {\n GET: { requireAuth: true, requireFeatures: ['customers.people.view'] },\n POST: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n PUT: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n DELETE: { requireAuth: true, requireFeatures: ['customers.people.manage'] },\n}\n\nexport const metadata = routeMetadata\n\nconst crud = makeCrudRoute({\n metadata: routeMetadata,\n orm: {\n entity: CustomerEntity,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n enrichers: { entityId: 'customers.person' },\n indexer: { entityType: E.customers.customer_entity },\n list: {\n schema: listSchema,\n entityId: E.customers.customer_entity,\n fields: [\n 'id',\n 'display_name',\n 'description',\n 'owner_user_id',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_at',\n 'next_interaction_name',\n 'next_interaction_ref_id',\n 'next_interaction_icon',\n 'next_interaction_color',\n 'organization_id',\n 'tenant_id',\n 'kind',\n 'created_at',\n ],\n sortFieldMap: {\n name: 'display_name',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n },\n buildFilters: async (query, ctx) => {\n const advancedFilterTree = consumeAdvancedFilterState(query)\n const filters: Record<string, unknown> = { kind: { $eq: 'person' } }\n if (query.id) filters.id = { $eq: query.id }\n if (query.search) {\n const matchingIds = ctx\n ? await findMatchingEntityIdsBySearchTokensAcrossSources({\n ctx,\n query: query.search,\n sources: [\n {\n entityType: E.customers.customer_entity,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'description',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'next_interaction_name',\n ],\n },\n {\n entityType: E.customers.customer_person_profile,\n fields: [\n 'display_name',\n 'primary_email',\n 'primary_phone',\n 'status',\n 'lifecycle_stage',\n 'source',\n 'first_name',\n 'last_name',\n 'preferred_name',\n 'job_title',\n 'department',\n 'seniority',\n 'timezone',\n 'linked_in_url',\n 'twitter_url',\n ],\n mapToEntityIds: {\n table: 'customer_people',\n targetColumn: 'entity_id',\n },\n },\n ],\n })\n : null\n if (matchingIds !== null && matchingIds.length > 0) {\n applyEntityIdRestriction(filters, matchingIds)\n } else {\n const searchPattern = `%${escapeLikePattern(query.search)}%`\n filters.$or = [\n { display_name: { $ilike: searchPattern } },\n { primary_email: { $ilike: searchPattern } },\n { primary_phone: { $ilike: searchPattern } },\n { description: { $ilike: searchPattern } },\n { next_interaction_name: { $ilike: searchPattern } },\n ]\n }\n }\n const email = typeof query.email === 'string' ? query.email.trim().toLowerCase() : ''\n const emailStartsWith = typeof query.emailStartsWith === 'string' ? query.emailStartsWith.trim().toLowerCase() : ''\n const emailContains = typeof query.emailContains === 'string' ? query.emailContains.trim().toLowerCase() : ''\n if (email) {\n filters.primary_email = { $eq: email }\n } else if (emailStartsWith) {\n filters.primary_email = { $ilike: `${escapeLikePattern(emailStartsWith)}%` }\n } else if (emailContains) {\n filters.primary_email = { $ilike: `%${escapeLikePattern(emailContains)}%` }\n }\n if (query.status) {\n filters.status = { $eq: query.status }\n }\n if (query.lifecycleStage) {\n filters.lifecycle_stage = { $eq: query.lifecycleStage }\n }\n if (query.source) {\n filters.source = { $eq: query.source }\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n const tagIdsEmpty = parseBooleanToken(query.tagIdsEmpty) === true\n if (tagIdsEmpty) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length > 0) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n }\n const excludedIds = new Set<string>()\n const excludeIdsRaw = typeof query.excludeIds === 'string' ? query.excludeIds : ''\n excludeIdsRaw\n .split(',')\n .map((value: string) => value.trim())\n .filter((value: string) => value.length > 0)\n .forEach((value: string) => excludedIds.add(value))\n if (ctx && query.excludeLinkedCompanyId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const linkWhere = await withActiveCustomerPersonCompanyLinkFilter(\n em,\n { company: query.excludeLinkedCompanyId },\n 'customers.people.GET',\n )\n const links = filterActivePersonCompanyLinks(\n await findWithDecryption(\n em,\n CustomerPersonCompanyLink,\n linkWhere,\n { populate: ['person'] },\n decryptionScope,\n ),\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n console.warn('[customers.people.list] exclusion lookup failed; falling back to base result set', err)\n }\n }\n if (ctx && query.excludeLinkedDealId) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const links = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n {\n deal: query.excludeLinkedDealId,\n },\n { populate: ['person'] },\n decryptionScope,\n )\n links.forEach((link) => {\n const personId = link.person?.id\n if (typeof personId === 'string' && personId.length > 0) excludedIds.add(personId)\n })\n } catch (err) {\n console.warn('[customers.people.list] exclusion lookup failed; falling back to base result set', err)\n }\n }\n applyEntityIdExclusion(filters, Array.from(excludedIds))\n const hasEmail = parseBooleanToken(query.hasEmail)\n if (!email && !emailStartsWith && !emailContains && hasEmail !== null) {\n filters.primary_email = { $exists: hasEmail }\n }\n const hasPhone = parseBooleanToken(query.hasPhone)\n if (hasPhone !== null) {\n filters.primary_phone = { $exists: hasPhone }\n }\n const hasNextInteraction = parseBooleanToken(query.hasNextInteraction)\n if (hasNextInteraction !== null) {\n filters.next_interaction_at = { $exists: hasNextInteraction }\n }\n const createdRange: Record<string, Date> = {}\n if (query.createdFrom) {\n const from = new Date(query.createdFrom)\n if (!Number.isNaN(from.getTime())) createdRange.$gte = from\n }\n if (query.createdTo) {\n const to = new Date(query.createdTo)\n if (!Number.isNaN(to.getTime())) createdRange.$lte = to\n }\n if (Object.keys(createdRange).length) {\n filters.created_at = createdRange\n }\n if (ctx) {\n try {\n const em = ctx.container.resolve('em') as EntityManager\n const cfFilters = await buildCustomFieldFiltersFromQuery({\n entityIds: [E.customers.customer_entity, E.customers.customer_person_profile],\n query,\n em,\n tenantId: ctx.auth?.tenantId ?? null,\n })\n Object.assign(filters, cfFilters)\n } catch (err) {\n console.warn('[customers.people.list] custom field filter resolution failed; falling back to base filters', err)\n }\n }\n if (ctx && advancedFilterTree) {\n const advancedFilters = mergeAdvancedFilterTree({ ...filters }, advancedFilterTree)\n const matchedIds = await findMatchingEntityIdsWithQueryEngine({\n ctx,\n entityId: E.customers.customer_entity,\n filters: advancedFilters,\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n })\n applyEntityIdRestriction(filters, matchedIds)\n }\n return filters\n },\n customFieldSources: [\n {\n entityId: E.customers.customer_person_profile,\n table: 'customer_people',\n alias: 'person_profile',\n recordIdColumn: 'id',\n join: { fromField: 'id', toField: 'entity_id' },\n },\n ],\n joins: [\n {\n alias: 'tag_assignments',\n table: 'customer_tag_assignments',\n from: { field: 'id' },\n to: { field: 'entity_id' },\n type: 'left',\n },\n ],\n transformItem: (item) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const normalized: Record<string, unknown> = { ...record }\n delete normalized.kind\n const cfEntries = extractAllCustomFieldEntries(record)\n for (const key of Object.keys(normalized)) {\n if (key.startsWith('cf:')) {\n delete normalized[key]\n }\n }\n return { ...normalized, ...cfEntries }\n },\n },\n actions: {\n create: {\n commandId: 'customers.people.create',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const { base, custom } = splitCustomFieldPayload(scoped)\n const parsed = personCreateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: ({ result }) => ({\n id: result?.entityId ?? result?.id ?? null,\n personId: result?.personId ?? null,\n }),\n status: 201,\n },\n update: {\n commandId: 'customers.people.update',\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }) => {\n const { translate } = await resolveTranslations()\n const scoped = withScopedPayload(raw ?? {}, ctx, translate)\n const normalized = normalizeProfilePayload(scoped, translate)\n const { base, custom } = splitCustomFieldPayload(normalized)\n const parsed = personUpdateSchema.parse(base)\n return Object.keys(custom).length ? { ...parsed, customFields: custom } : parsed\n },\n response: () => ({ ok: true }),\n },\n delete: {\n commandId: 'customers.people.delete',\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }) => {\n const { translate } = await resolveTranslations()\n const id =\n parsed?.body?.id ??\n parsed?.id ??\n parsed?.query?.id ??\n (ctx.request ? new URL(ctx.request.url).searchParams.get('id') : null)\n if (!id) throw new CrudHttpError(400, { error: translate('customers.errors.person_required', 'Person id is required') })\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload, ctx) => {\n const items = Array.isArray(payload?.items) ? payload.items : []\n const ids = items\n .map((item: unknown) => (\n item && typeof item === 'object' && typeof (item as Record<string, unknown>).id === 'string'\n ? (item as Record<string, unknown>).id as string\n : null\n ))\n .filter((id: string | null): id is string => typeof id === 'string' && id.length > 0)\n if (!ids.length) return\n\n const em = ctx.container.resolve('em') as EntityManager\n const decryptionScope = {\n tenantId: ctx.auth?.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? ctx.auth?.orgId ?? null,\n }\n const entities = await findWithDecryption(\n em,\n CustomerEntity,\n {\n id: { $in: ids },\n deletedAt: null,\n kind: 'person',\n } as FilterQuery<CustomerEntity>,\n undefined,\n decryptionScope,\n )\n const entitiesById = new Map<string, CustomerEntity>()\n for (const entity of entities) {\n entitiesById.set(entity.id, entity)\n }\n\n const where: Record<string, unknown> = {\n entity: { $in: ids },\n tenantId: ctx.auth?.tenantId ?? null,\n }\n if (ctx.selectedOrganizationId) {\n where.organizationId = ctx.selectedOrganizationId\n }\n\n const profiles = await findWithDecryption(\n em,\n CustomerPersonProfile,\n where as FilterQuery<CustomerPersonProfile>,\n { populate: ['entity', 'company'] },\n decryptionScope,\n )\n\n const profilesByEntityId = new Map<string, CustomerPersonProfile>()\n for (const profile of profiles) {\n const profileEntity = (profile as { entity?: { id?: unknown } }).entity\n const entityId = typeof profileEntity?.id === 'string' ? profileEntity.id : null\n if (entityId) profilesByEntityId.set(entityId, profile)\n }\n\n payload.items = items.map((item: unknown) => {\n if (!item || typeof item !== 'object') return item\n const record = item as Record<string, unknown>\n const entity = typeof record.id === 'string' ? entitiesById.get(record.id) : undefined\n const profile = typeof record.id === 'string' ? profilesByEntityId.get(record.id) : undefined\n if (!entity && !profile) return item\n return {\n ...record,\n display_name: entity?.displayName ?? record.display_name ?? null,\n description: entity?.description ?? record.description ?? null,\n owner_user_id: entity?.ownerUserId ?? record.owner_user_id ?? null,\n primary_email: entity?.primaryEmail ?? record.primary_email ?? null,\n primary_phone: entity?.primaryPhone ?? record.primary_phone ?? null,\n status: entity?.status ?? record.status ?? null,\n lifecycle_stage: entity?.lifecycleStage ?? record.lifecycle_stage ?? null,\n source: entity?.source ?? record.source ?? null,\n next_interaction_at: entity?.nextInteractionAt ? entity.nextInteractionAt.toISOString() : record.next_interaction_at ?? null,\n next_interaction_name: entity?.nextInteractionName ?? record.next_interaction_name ?? null,\n next_interaction_ref_id: entity?.nextInteractionRefId ?? record.next_interaction_ref_id ?? null,\n next_interaction_icon: entity?.nextInteractionIcon ?? record.next_interaction_icon ?? null,\n next_interaction_color: entity?.nextInteractionColor ?? record.next_interaction_color ?? null,\n first_name: profile?.firstName ?? null,\n last_name: profile?.lastName ?? null,\n preferred_name: profile?.preferredName ?? null,\n job_title: profile?.jobTitle ?? null,\n department: profile?.department ?? null,\n seniority: profile?.seniority ?? null,\n timezone: profile?.timezone ?? null,\n linked_in_url: profile?.linkedInUrl ?? null,\n twitter_url: profile?.twitterUrl ?? null,\n company_entity_id:\n profile?.company && typeof profile.company === 'object'\n ? profile.company.id\n : profile?.company ?? null,\n }\n })\n },\n },\n})\n\nconst { POST, PUT, DELETE } = crud\n\nexport { POST, PUT, DELETE }\nexport const GET = crud.GET\n\nconst personListItemSchema = z.object({\n id: z.string().uuid(),\n display_name: z.string().optional(),\n description: z.string().nullable().optional(),\n owner_user_id: z.string().uuid().nullable().optional(),\n primary_email: z.string().nullable().optional(),\n primary_phone: z.string().nullable().optional(),\n status: z.string().nullable().optional(),\n lifecycle_stage: z.string().nullable().optional(),\n source: z.string().nullable().optional(),\n next_interaction_at: z.string().nullable().optional(),\n next_interaction_name: z.string().nullable().optional(),\n next_interaction_ref_id: z.string().nullable().optional(),\n next_interaction_icon: z.string().nullable().optional(),\n next_interaction_color: z.string().nullable().optional(),\n organization_id: z.string().uuid().nullable().optional(),\n tenant_id: z.string().uuid().nullable().optional(),\n created_at: z.string().nullable().optional(),\n})\n\nconst personCreateResponseSchema = z.object({\n id: z.string().uuid().nullable(),\n personId: z.string().uuid().nullable(),\n})\n\nexport const openApi = createCustomersCrudOpenApi({\n resourceName: 'Person',\n pluralName: 'People',\n querySchema: listSchema,\n listResponseSchema: createPagedListResponseSchema(personListItemSchema),\n create: {\n schema: personCreateSchema,\n responseSchema: personCreateResponseSchema,\n description: 'Creates a person contact using scoped organization and tenant identifiers.',\n },\n update: {\n schema: personUpdateSchema,\n responseSchema: defaultOkResponseSchema,\n description: 'Updates contact details or custom fields for a person.',\n },\n del: {\n schema: z.object({ id: z.string().uuid() }),\n responseSchema: defaultOkResponseSchema,\n description: 'Deletes a person by id. Request body or query may provide the identifier.',\n errors: [\n {\n status: 422,\n description: 'Person has dependent records (e.g. linked deals); unlink or reassign before delete.',\n schema: z.object({\n error: z.string(),\n code: z.literal('PERSON_HAS_DEPENDENTS'),\n }),\n },\n ],\n },\n})\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -35,6 +35,7 @@ const crud = makeCrudRoute({
35
35
  orgField: "organizationId",
36
36
  tenantField: "tenantId"
37
37
  },
38
+ indexer: { entityType: E.customers.customer_tag },
38
39
  list: {
39
40
  schema: listSchema,
40
41
  entityId: E.customers.customer_tag,