@open-mercato/core 0.7.1-develop.7113.1.9d83dca10c → 0.7.1-develop.7121.1.734c263bda
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.
- package/.turbo/turbo-build.log +1 -1
- package/dist/helpers/integration/crmFixtures.js.map +1 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js +9 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/test-send/route.js.map +2 -2
- package/dist/modules/communication_channels/lib/outbound-recipient.js +5 -1
- package/dist/modules/communication_channels/lib/outbound-recipient.js.map +2 -2
- package/dist/modules/communication_channels/lib/test-seed.js +5 -0
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +1 -1
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +1 -1
- package/dist/modules/customers/backend/customers/deals/page.js +4 -3
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js +1 -1
- package/dist/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.js.map +1 -1
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js +1 -1
- package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
- package/dist/modules/customers/cli.js +5 -5
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/components/detail/pipelineStageUtils.js +1 -0
- package/dist/modules/customers/components/detail/pipelineStageUtils.js.map +2 -2
- package/dist/modules/customers/components/linking/adapters/dealAdapter.js +2 -2
- package/dist/modules/customers/components/linking/adapters/dealAdapter.js.map +2 -2
- package/dist/modules/customers/lib/closureStage.js.map +2 -2
- package/dist/modules/customers/lib/dealStatus.js +6 -4
- package/dist/modules/customers/lib/dealStatus.js.map +2 -2
- package/dist/modules/customers/lib/dealsSummaryQueries.js +3 -3
- package/dist/modules/customers/lib/dealsSummaryQueries.js.map +1 -1
- package/dist/modules/customers/migrations/Migration20260824180000_deal_status_lost.js +30 -0
- package/dist/modules/customers/migrations/Migration20260824180000_deal_status_lost.js.map +7 -0
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/config.js.map +1 -1
- package/dist/modules/eudr/notifications.js +5 -0
- package/dist/modules/eudr/notifications.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +59 -28
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +146 -99
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +1 -30
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +1 -4
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js +2 -1
- package/dist/modules/sales/components/documents/SalesOrderDraftLines.js.map +2 -2
- package/dist/modules/sales/data/validators.js +3 -0
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/lib/calculations.js +14 -2
- package/dist/modules/sales/lib/calculations.js.map +2 -2
- package/dist/modules/sales/lib/json.js +8 -0
- package/dist/modules/sales/lib/json.js.map +7 -0
- package/dist/modules/sales/lib/lineSnapshots.js +66 -0
- package/dist/modules/sales/lib/lineSnapshots.js.map +7 -0
- package/dist/modules/warranty_claims/notifications.js +5 -0
- package/dist/modules/warranty_claims/notifications.js.map +2 -2
- package/dist/modules/wms/notifications.js +2 -0
- package/dist/modules/wms/notifications.js.map +2 -2
- package/package.json +7 -7
- package/src/helpers/integration/crmFixtures.ts +1 -1
- package/src/modules/communication_channels/api/post/channels/[id]/test-send/route.ts +21 -9
- package/src/modules/communication_channels/lib/adapter.ts +11 -0
- package/src/modules/communication_channels/lib/outbound-recipient.ts +14 -1
- package/src/modules/communication_channels/lib/test-seed.ts +19 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +1 -1
- package/src/modules/customers/backend/customers/deals/page.tsx +4 -3
- package/src/modules/customers/backend/customers/deals/pipeline/components/QuickDealDialog.tsx +5 -5
- package/src/modules/customers/backend/customers/deals/pipeline/components/StatusFilterPopover.tsx +3 -3
- package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +2 -2
- package/src/modules/customers/cli.ts +5 -5
- package/src/modules/customers/commands/deals.ts +4 -3
- package/src/modules/customers/components/detail/pipelineStageUtils.ts +1 -0
- package/src/modules/customers/components/linking/adapters/dealAdapter.tsx +2 -2
- package/src/modules/customers/i18n/de.json +1 -1
- package/src/modules/customers/i18n/en.json +1 -1
- package/src/modules/customers/i18n/es.json +1 -1
- package/src/modules/customers/i18n/ko.json +1 -1
- package/src/modules/customers/i18n/pl.json +1 -1
- package/src/modules/customers/lib/closureStage.ts +2 -1
- package/src/modules/customers/lib/dealStatus.ts +23 -12
- package/src/modules/customers/lib/dealsSummaryQueries.ts +3 -3
- package/src/modules/customers/migrations/Migration20260824180000_deal_status_lost.ts +55 -0
- package/src/modules/dashboards/widgets/dashboard/pipeline-summary/config.ts +1 -1
- package/src/modules/eudr/notifications.ts +5 -0
- package/src/modules/query_index/lib/search-tokens.ts +100 -43
- package/src/modules/sales/commands/documents.ts +185 -105
- package/src/modules/sales/commands/returns.ts +1 -31
- package/src/modules/sales/commands/shared.ts +1 -4
- package/src/modules/sales/components/documents/SalesOrderDraftLines.tsx +12 -1
- package/src/modules/sales/data/validators.ts +3 -0
- package/src/modules/sales/lib/calculations.ts +33 -7
- package/src/modules/sales/lib/json.ts +4 -0
- package/src/modules/sales/lib/lineSnapshots.ts +98 -0
- package/src/modules/sales/lib/types.ts +20 -0
- package/src/modules/warranty_claims/notifications.ts +5 -0
- package/src/modules/wms/notifications.ts +2 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/commands/deals.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n normalizeAuthorUserId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { runCrudCommandWrite } from '@open-mercato/shared/lib/commands/runCrudCommandWrite'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerDeal,\n CustomerDealPersonLink,\n CustomerDealCompanyLink,\n CustomerDealStageTransition,\n CustomerPipelineStage,\n} from '../data/entities'\nimport {\n dealCreateSchema,\n dealUpdateSchema,\n type DealCreateInput,\n type DealUpdateInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n requireCustomerEntity,\n ensureSameScope,\n extractUndoPayload,\n ensureDictionaryEntry,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n type CustomFieldChangeSet,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isMissingDealStageTransitionTable, warnMissingDealStageTransitionTable } from '../lib/dealStageTransitionTable'\nimport {\n dealClosureOutcomeFromStatus,\n loadClosurePipelineStageSnapshot,\n type DealClosureOutcome,\n type PipelineStageSnapshot,\n} from '../lib/closureStage'\nimport { canonicalDealStatus, isClosedDealStatus } from '../lib/dealStatus'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst DEAL_ENTITY_ID = 'customers:customer_deal'\nconst dealCrudIndexer: CrudIndexerConfig<CustomerDeal> = {\n entityType: E.customers.customer_deal,\n}\n\nconst dealCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'deal',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype DealStageTransitionSnapshot = {\n id: string\n pipelineId: string\n stageId: string\n stageLabel: string\n stageOrder: number\n transitionedAt: Date | string\n transitionedByUserId: string | null\n}\n\nfunction coerceSnapshotDate(value: Date | string | null | undefined, fieldName: string): Date | null {\n if (value === undefined || value === null) return null\n if (value instanceof Date) return value\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) {\n throw new Error(`[internal] Invalid ${fieldName} undo snapshot date: ${value}`)\n }\n return date\n}\n\nfunction coerceRequiredSnapshotDate(value: Date | string, fieldName: string): Date {\n const date = coerceSnapshotDate(value, fieldName)\n if (!date) {\n throw new Error(`[internal] Missing ${fieldName} undo snapshot date`)\n }\n return date\n}\n\nasync function loadPipelineStageSnapshot(\n em: EntityManager,\n pipelineStageId: string,\n tenantId: string,\n organizationId: string,\n): Promise<PipelineStageSnapshot | null> {\n const stage = await findOneWithDecryption(em, CustomerPipelineStage, { id: pipelineStageId }, {}, { tenantId, organizationId })\n if (!stage) return null\n return {\n id: stage.id,\n pipelineId: stage.pipelineId,\n label: stage.label,\n order: stage.order,\n }\n}\n\nfunction resolveRequestedClosureOutcome(input: DealUpdateInput): DealClosureOutcome | null {\n if (input.closureOutcome === 'won' || input.closureOutcome === 'lost') {\n return input.closureOutcome\n }\n // `win` / `loose` are what the UI closure flows persist; `won` / `lost` are the\n // spellings the AI stage tool persists. Both must derive the same closure outcome so\n // every closed deal lands in the pipeline's terminal stage (#5107).\n return dealClosureOutcomeFromStatus(input.status)\n}\n\nasync function resolvePipelineStageValue(\n em: EntityManager,\n pipelineStageId: string,\n tenantId: string,\n organizationId: string,\n): Promise<string | null> {\n const stage = await loadPipelineStageSnapshot(em, pipelineStageId, tenantId, organizationId)\n if (!stage) return null\n const entry = await ensureDictionaryEntry(em, {\n tenantId,\n organizationId,\n kind: 'pipeline_stage',\n value: stage.label,\n })\n return entry?.value ?? stage.label\n}\n\nfunction resolvePipelineAssignment(input: {\n pipelineId?: string | null\n pipelineStageId?: string | null\n stageSnapshot: PipelineStageSnapshot | null\n}): { pipelineId: string | null; pipelineStageId: string | null } {\n const requestedPipelineId = input.pipelineId ?? null\n const requestedPipelineStageId = input.pipelineStageId ?? null\n\n if (requestedPipelineStageId && !input.stageSnapshot) {\n throw new CrudHttpError(400, { error: 'Pipeline stage not found' })\n }\n\n if (\n requestedPipelineId &&\n input.stageSnapshot &&\n input.stageSnapshot.pipelineId !== requestedPipelineId\n ) {\n throw new CrudHttpError(400, {\n error: 'Pipeline stage does not belong to the selected pipeline',\n })\n }\n\n return {\n pipelineId: requestedPipelineId ?? input.stageSnapshot?.pipelineId ?? null,\n pipelineStageId: requestedPipelineStageId,\n }\n}\n\nasync function upsertDealStageTransition(\n em: EntityManager,\n input: {\n deal: CustomerDeal\n pipelineId: string\n stageId: string\n stageLabel: string\n stageOrder: number\n transitionedByUserId: string | null\n transitionedAt?: Date\n },\n): Promise<void> {\n let existing: CustomerDealStageTransition | null = null\n try {\n existing = await findOneWithDecryption(\n em,\n CustomerDealStageTransition,\n { deal: input.deal.id, stageId: input.stageId, deletedAt: null },\n {},\n { tenantId: input.deal.tenantId, organizationId: input.deal.organizationId },\n )\n } catch (error) {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.upsertTransition')\n return\n }\n const transitionedAt = input.transitionedAt ?? new Date()\n if (existing) {\n existing.pipelineId = input.pipelineId\n existing.stageLabel = input.stageLabel\n existing.stageOrder = input.stageOrder\n existing.transitionedAt = transitionedAt\n existing.transitionedByUserId = input.transitionedByUserId\n existing.deletedAt = null\n existing.isActive = true\n return\n }\n\n const transition = em.create(CustomerDealStageTransition, {\n organizationId: input.deal.organizationId,\n tenantId: input.deal.tenantId,\n deal: input.deal,\n pipelineId: input.pipelineId,\n stageId: input.stageId,\n stageLabel: input.stageLabel,\n stageOrder: input.stageOrder,\n transitionedAt,\n transitionedByUserId: input.transitionedByUserId,\n isActive: true,\n })\n em.persist(transition)\n}\n\nasync function deleteDealStageTransitions(em: EntityManager, deal: CustomerDeal): Promise<void> {\n try {\n await em.nativeDelete(CustomerDealStageTransition, { deal: deal.id })\n } catch (error) {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.deleteTransitions')\n }\n}\n\nasync function restoreDealStageTransitions(\n em: EntityManager,\n deal: CustomerDeal,\n transitions: DealStageTransitionSnapshot[],\n): Promise<void> {\n if (!transitions.length) return\n for (const transitionSnapshot of transitions) {\n const transition = em.create(CustomerDealStageTransition, {\n id: transitionSnapshot.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n deal,\n pipelineId: transitionSnapshot.pipelineId,\n stageId: transitionSnapshot.stageId,\n stageLabel: transitionSnapshot.stageLabel,\n stageOrder: transitionSnapshot.stageOrder,\n transitionedAt: coerceRequiredSnapshotDate(transitionSnapshot.transitionedAt, 'transitionedAt'),\n transitionedByUserId: transitionSnapshot.transitionedByUserId,\n isActive: true,\n })\n em.persist(transition)\n }\n}\n\ntype DealSnapshot = {\n deal: {\n id: string\n organizationId: string\n tenantId: string\n title: string\n description: string | null\n status: string\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: string | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: Date | string | null\n ownerUserId: string | null\n source: string | null\n closureOutcome: string | null\n lossReasonId: string | null\n lossNotes: string | null\n }\n people: string[]\n primaryPersonEntityId?: string | null\n companies: string[]\n transitions: DealStageTransitionSnapshot[]\n custom?: Record<string, unknown>\n}\n\ntype DealUndoPayload = {\n before?: DealSnapshot | null\n after?: DealSnapshot | null\n}\n\ntype DealChangeMap = Record<string, { from: unknown; to: unknown }> & {\n custom?: CustomFieldChangeSet\n}\n\nasync function loadDealSnapshot(em: EntityManager, id: string): Promise<DealSnapshot | null> {\n const deal = await findOneWithDecryption(em, CustomerDeal, { id, deletedAt: null })\n if (!deal) return null\n const decryptionScope = { tenantId: deal.tenantId ?? null, organizationId: deal.organizationId ?? null }\n const peopleLinks = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n { deal: deal },\n { populate: ['person'] },\n decryptionScope,\n )\n const companyLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n { deal: deal },\n { populate: ['company'] },\n decryptionScope,\n )\n const transitions = await findWithDecryption(\n em,\n CustomerDealStageTransition,\n { deal: deal.id, deletedAt: null },\n { orderBy: { stageOrder: 'ASC', transitionedAt: 'ASC' } },\n decryptionScope,\n ).catch((error: unknown) => {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.loadSnapshot')\n return [] as CustomerDealStageTransition[]\n })\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n tenantId: deal.tenantId,\n organizationId: deal.organizationId,\n })\n const primaryPerson = peopleLinks.find((link) => link.isPrimary)?.person\n return {\n deal: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n title: deal.title,\n description: deal.description ?? null,\n status: deal.status,\n pipelineStage: deal.pipelineStage ?? null,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount ?? null,\n valueCurrency: deal.valueCurrency ?? null,\n probability: deal.probability ?? null,\n expectedCloseAt: deal.expectedCloseAt ?? null,\n ownerUserId: deal.ownerUserId ?? null,\n source: deal.source ?? null,\n closureOutcome: deal.closureOutcome ?? null,\n lossReasonId: deal.lossReasonId ?? null,\n lossNotes: deal.lossNotes ?? null,\n },\n people: peopleLinks.map((link) =>\n typeof link.person === 'string' ? link.person : link.person.id\n ),\n primaryPersonEntityId:\n typeof primaryPerson === 'string' ? primaryPerson : primaryPerson?.id ?? null,\n companies: companyLinks.map((link) =>\n typeof link.company === 'string' ? link.company : link.company.id\n ),\n transitions: transitions.map((transition) => ({\n id: transition.id,\n pipelineId: transition.pipelineId,\n stageId: transition.stageId,\n stageLabel: transition.stageLabel,\n stageOrder: transition.stageOrder,\n transitionedAt: transition.transitionedAt,\n transitionedByUserId: transition.transitionedByUserId ?? null,\n })),\n custom,\n }\n}\n\nfunction toNumericString(value: number | null | undefined): string | null {\n if (value === undefined || value === null) return null\n return value.toString()\n}\n\nasync function syncDealPeople(\n em: EntityManager,\n deal: CustomerDeal,\n personIds: string[] | undefined | null,\n primaryPersonEntityId?: string | null\n): Promise<void> {\n if (personIds === undefined) {\n if (primaryPersonEntityId === undefined) return\n const links = await em.find(CustomerDealPersonLink, { deal })\n if (primaryPersonEntityId !== null && !links.some((link) => link.person.id === primaryPersonEntityId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate(\n 'customers.errors.primaryPersonMustBeLinked',\n 'Primary person must be linked to the deal',\n ),\n })\n }\n for (const link of links) {\n link.isPrimary = false\n }\n await em.flush()\n if (primaryPersonEntityId !== null) {\n const primaryLink = links.find((link) => link.person.id === primaryPersonEntityId)\n if (primaryLink) primaryLink.isPrimary = true\n }\n return\n }\n const unique = Array.from(new Set(personIds ?? []))\n if (primaryPersonEntityId !== undefined && primaryPersonEntityId !== null && !unique.includes(primaryPersonEntityId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate(\n 'customers.errors.primaryPersonMustBeLinked',\n 'Primary person must be linked to the deal',\n ),\n })\n }\n let effectivePrimaryId = primaryPersonEntityId\n if (effectivePrimaryId === undefined) {\n const existingPrimary = await em.findOne(CustomerDealPersonLink, { deal, isPrimary: true })\n effectivePrimaryId = existingPrimary?.person?.id ?? null\n }\n await em.nativeDelete(CustomerDealPersonLink, { deal })\n if (!unique.length) return\n for (const personId of unique) {\n const person = await requireCustomerEntity(em, personId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'person', 'Person not found')\n ensureSameScope(person, deal.organizationId, deal.tenantId)\n const link = em.create(CustomerDealPersonLink, {\n deal,\n person,\n isPrimary: personId === effectivePrimaryId,\n })\n em.persist(link)\n }\n}\n\nasync function syncDealCompanies(\n em: EntityManager,\n deal: CustomerDeal,\n companyIds: string[] | undefined | null\n): Promise<void> {\n if (companyIds === undefined) return\n await em.nativeDelete(CustomerDealCompanyLink, { deal })\n if (!companyIds || !companyIds.length) return\n const unique = Array.from(new Set(companyIds))\n for (const companyId of unique) {\n const company = await requireCustomerEntity(em, companyId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'company', 'Company not found')\n ensureSameScope(company, deal.organizationId, deal.tenantId)\n const link = em.create(CustomerDealCompanyLink, {\n deal,\n company,\n })\n em.persist(link)\n }\n}\n\nconst createDealCommand: CommandHandler<DealCreateInput, { dealId: string }> = {\n id: 'customers.deals.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(dealCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n let deal!: CustomerDeal\n let stageSnapshot: PipelineStageSnapshot | null = null\n let pipelineAssignment: { pipelineId: string | null; pipelineStageId: string | null } = {\n pipelineId: null,\n pipelineStageId: null,\n }\n let resolvedPipelineStageLabel: string | null = null\n await withAtomicFlush(em, [\n async () => {\n stageSnapshot = parsed.pipelineStageId\n ? await loadPipelineStageSnapshot(em, parsed.pipelineStageId, parsed.tenantId, parsed.organizationId)\n : null\n pipelineAssignment = resolvePipelineAssignment({\n pipelineId: parsed.pipelineId,\n pipelineStageId: parsed.pipelineStageId,\n stageSnapshot,\n })\n resolvedPipelineStageLabel = stageSnapshot\n ? (await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'pipeline_stage',\n value: stageSnapshot.label,\n }))?.value ?? stageSnapshot.label\n : parsed.pipelineStage ?? null\n },\n async () => {\n deal = em.create(CustomerDeal, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n title: parsed.title,\n description: parsed.description ?? null,\n status: parsed.status ?? 'open',\n pipelineStage: resolvedPipelineStageLabel,\n pipelineId: pipelineAssignment.pipelineId,\n pipelineStageId: pipelineAssignment.pipelineStageId,\n valueAmount: toNumericString(parsed.valueAmount),\n valueCurrency: parsed.valueCurrency ?? null,\n probability: parsed.probability ?? null,\n expectedCloseAt: parsed.expectedCloseAt ?? null,\n ownerUserId: parsed.ownerUserId ?? null,\n source: parsed.source ?? null,\n closureOutcome: parsed.closureOutcome ?? null,\n lossReasonId: parsed.lossReasonId ?? null,\n lossNotes: parsed.lossNotes ?? null,\n })\n em.persist(deal)\n await em.flush()\n },\n async () => {\n const snapshot = stageSnapshot\n if (!snapshot) return\n await upsertDealStageTransition(em, {\n deal,\n pipelineId: snapshot.pipelineId,\n stageId: snapshot.id,\n stageLabel: snapshot.label,\n stageOrder: snapshot.order,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, deal, parsed.personIds ?? [], parsed.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, parsed.companyIds ?? []),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: custom,\n notify: false,\n })\n\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n return { dealId: deal.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadDealSnapshot(em, result.dealId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, result.dealId)\n return {\n actionLabel: translate('customers.audit.deals.create', 'Create deal'),\n resourceKind: 'customers.deal',\n resourceId: result.dealId,\n tenantId: snapshot?.deal.tenantId ?? null,\n organizationId: snapshot?.deal.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const dealId = logEntry?.resourceId\n if (!dealId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id: dealId })\n if (!deal) return\n await deleteDealStageTransitions(em, deal)\n await em.nativeDelete(CustomerDealPersonLink, { deal })\n await em.nativeDelete(CustomerDealCompanyLink, { deal })\n em.remove(deal)\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<DealSnapshot>(logEntry)\n if (!after) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for deal create' })\n }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: after.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: after.deal.id,\n organizationId: after.deal.organizationId,\n tenantId: after.deal.tenantId,\n title: after.deal.title,\n description: after.deal.description,\n status: after.deal.status,\n pipelineStage: after.deal.pipelineStage,\n pipelineId: after.deal.pipelineId,\n pipelineStageId: after.deal.pipelineStageId,\n valueAmount: after.deal.valueAmount,\n valueCurrency: after.deal.valueCurrency,\n probability: after.deal.probability,\n expectedCloseAt: after.deal.expectedCloseAt,\n ownerUserId: after.deal.ownerUserId,\n source: after.deal.source,\n closureOutcome: after.deal.closureOutcome,\n lossReasonId: after.deal.lossReasonId,\n lossNotes: after.deal.lossNotes,\n })\n em.persist(deal)\n }\n const restoredDeal = deal\n await withAtomicFlush(em, [\n () => syncDealPeople(em, restoredDeal, after.people, after.primaryPersonEntityId),\n () => syncDealCompanies(em, restoredDeal, after.companies),\n () => deleteDealStageTransitions(em, restoredDeal),\n () => restoreDealStageTransitions(em, restoredDeal, after.transitions),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: restoredDeal,\n identifiers: {\n id: restoredDeal.id,\n organizationId: restoredDeal.organizationId,\n tenantId: restoredDeal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const restoreValues = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(restoreValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: restoredDeal.id,\n organizationId: restoredDeal.organizationId,\n tenantId: restoredDeal.tenantId,\n values: restoreValues,\n notify: false,\n })\n }\n\n return { dealId: restoredDeal.id }\n },\n}\n\nconst updateDealCommand: CommandHandler<DealUpdateInput, { dealId: string }> = {\n id: 'customers.deals.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(dealUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(dealUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id: parsed.id, deletedAt: null })\n const record = deal ?? null\n if (!record) throw notFound('Deal not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n const previousStatus = record.status\n const previousPipelineStageId = record.pipelineStageId ?? null\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n\n let nextStageSnapshot: PipelineStageSnapshot | null = null\n let nextPipelineAssignment: { pipelineId: string | null; pipelineStageId: string | null } = {\n pipelineId: record.pipelineId ?? null,\n pipelineStageId: record.pipelineStageId ?? null,\n }\n let nextPipelineStageLabel: string | null = null\n let resolvedCurrentPipelineStageLabel: string | null = null\n let pipelineStageAssignmentChanged = false\n let requestedClosureOutcome: DealClosureOutcome | null = null\n\n await runCrudCommandWrite({\n ctx,\n em,\n entityId: DEAL_ENTITY_ID,\n action: 'updated',\n scope: { tenantId: record.tenantId, organizationId: record.organizationId },\n customFields: custom,\n events: dealCrudEvents,\n indexer: dealCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n async () => {\n requestedClosureOutcome = resolveRequestedClosureOutcome(parsed)\n const requestedPipelineId =\n parsed.pipelineId !== undefined ? parsed.pipelineId ?? null : record.pipelineId ?? null\n const closureStageSnapshot =\n parsed.pipelineStageId === undefined && requestedClosureOutcome\n ? await loadClosurePipelineStageSnapshot(em, {\n pipelineId: requestedPipelineId,\n closureOutcome: requestedClosureOutcome,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n : null\n pipelineStageAssignmentChanged =\n parsed.pipelineStageId !== undefined || closureStageSnapshot !== null\n const pipelineAssignmentChanged =\n parsed.pipelineId !== undefined || pipelineStageAssignmentChanged\n const requestedPipelineStageId =\n parsed.pipelineStageId !== undefined\n ? parsed.pipelineStageId ?? null\n : closureStageSnapshot?.id ?? record.pipelineStageId ?? null\n\n nextStageSnapshot = closureStageSnapshot ?? (\n requestedPipelineStageId && (pipelineAssignmentChanged || !record.pipelineStage)\n ? await loadPipelineStageSnapshot(em, requestedPipelineStageId, record.tenantId, record.organizationId)\n : null\n )\n if (pipelineAssignmentChanged) {\n nextPipelineAssignment = resolvePipelineAssignment({\n pipelineId: requestedPipelineId,\n pipelineStageId: requestedPipelineStageId,\n stageSnapshot: nextStageSnapshot,\n })\n }\n nextPipelineStageLabel = nextStageSnapshot\n ? (await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'pipeline_stage',\n value: nextStageSnapshot.label,\n }))?.value ?? nextStageSnapshot.label\n : null\n resolvedCurrentPipelineStageLabel =\n !nextStageSnapshot && record.pipelineStageId && (parsed.pipelineStageId !== undefined || !record.pipelineStage)\n ? await resolvePipelineStageValue(em, record.pipelineStageId, record.tenantId, record.organizationId)\n : null\n },\n () => {\n if (parsed.title !== undefined) record.title = parsed.title\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.status !== undefined) record.status = parsed.status ?? record.status\n if (parsed.pipelineStage !== undefined) record.pipelineStage = parsed.pipelineStage ?? null\n if (parsed.pipelineId !== undefined || (pipelineStageAssignmentChanged && nextStageSnapshot)) {\n record.pipelineId = nextPipelineAssignment.pipelineId\n }\n if (pipelineStageAssignmentChanged) record.pipelineStageId = nextPipelineAssignment.pipelineStageId\n\n if (nextPipelineStageLabel && (pipelineStageAssignmentChanged || !record.pipelineStage)) {\n record.pipelineStage = nextPipelineStageLabel\n } else if (resolvedCurrentPipelineStageLabel && (pipelineStageAssignmentChanged || !record.pipelineStage)) {\n record.pipelineStage = resolvedCurrentPipelineStageLabel\n }\n\n if (parsed.valueAmount !== undefined) record.valueAmount = toNumericString(parsed.valueAmount)\n if (parsed.valueCurrency !== undefined) record.valueCurrency = parsed.valueCurrency ?? null\n if (parsed.probability !== undefined) record.probability = parsed.probability ?? null\n if (parsed.expectedCloseAt !== undefined) record.expectedCloseAt = parsed.expectedCloseAt ?? null\n if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.source !== undefined) record.source = parsed.source ?? null\n if (parsed.closureOutcome !== undefined) record.closureOutcome = parsed.closureOutcome ?? null\n // Derive the outcome only when the status spelling alone drives the closure \u2014\n // the same condition that triggers the terminal-stage move below \u2014 so an\n // explicit non-terminal pipelineStageId never produces a half-closed state.\n else if (requestedClosureOutcome && parsed.pipelineStageId === undefined) {\n record.closureOutcome = requestedClosureOutcome\n } else if (\n parsed.status !== undefined &&\n !requestedClosureOutcome &&\n // `closed` is a seeded dictionary status: saving it is not a reopen, so only\n // a genuinely non-closed status clears stored closure state \u2014 and only when\n // the deal actually carries any (a no-op status echo must not wipe loss data).\n // Canonicalize first: `dealClosureOutcomeFromStatus` above already matches\n // case-insensitively, so matching `closed` exactly would let `Closed` through\n // this guard and null the operator's loss notes.\n !isClosedDealStatus(canonicalDealStatus(parsed.status)) &&\n record.closureOutcome !== null\n ) {\n record.closureOutcome = null\n if (parsed.lossReasonId === undefined) record.lossReasonId = null\n if (parsed.lossNotes === undefined) record.lossNotes = null\n }\n if (parsed.lossReasonId !== undefined) record.lossReasonId = parsed.lossReasonId ?? null\n if (parsed.lossNotes !== undefined) record.lossNotes = parsed.lossNotes ?? null\n },\n async () => {\n // CRITICAL: persist the scalar mutations above before any further `em.findOne` / sync\n // helpers run inside this transaction. MikroORM v7's identity-map silently discards\n // pending scalar changes on `record` if a query (such as the stage-transition lookup\n // inside `upsertDealStageTransition`, or the linked-entity finds inside\n // `syncDealPeople` / `syncDealCompanies`) executes on the same `EntityManager`\n // before we explicitly flush. Without this flush, the entire kanban drag-and-drop\n // returns 200 OK but never actually updates `customer_deals` rows \u2014 the card\n // snaps back to its source lane on the next refetch (see SPEC-018).\n await em.flush()\n },\n async () => {\n const snapshot = nextStageSnapshot\n if (!snapshot) return\n const shouldRecord =\n pipelineStageAssignmentChanged &&\n nextPipelineAssignment.pipelineStageId !== null &&\n nextPipelineAssignment.pipelineStageId !== previousPipelineStageId\n if (!shouldRecord) return\n await upsertDealStageTransition(em, {\n deal: record,\n pipelineId: snapshot.pipelineId,\n stageId: snapshot.id,\n stageLabel: nextPipelineStageLabel ?? snapshot.label,\n stageOrder: snapshot.order,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, record, parsed.personIds, parsed.primaryPersonEntityId),\n () => syncDealCompanies(em, record, parsed.companyIds),\n ],\n })\n\n // Emit a lifecycle event for deal won/lost status changes; the notifications\n // subscriber translates these into recipient notifications. Tenant/organization\n // scope MUST travel in the emit options, not only in the payload: both delivery\n // paths build the subscriber context from `options` alone, so wildcard\n // subscribers (workflow event triggers, business-rules triggers) drop a\n // null-scoped event before trigger matching.\n const newStatus = record.status\n const normalizedStatus = newStatus === 'win' ? 'won' : newStatus === 'loose' ? 'lost' : newStatus\n if (previousStatus !== newStatus && (normalizedStatus === 'won' || normalizedStatus === 'lost')) {\n const closureEvent = normalizedStatus === 'won' ? 'customers.deal.won' : 'customers.deal.lost'\n try {\n const eventBus = ctx.container.resolve('eventBus') as { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> } | undefined\n if (eventBus) {\n await eventBus.emitEvent(\n closureEvent,\n {\n id: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n ownerUserId: record.ownerUserId ?? null,\n title: record.title,\n valueAmount: record.valueAmount ?? null,\n valueCurrency: record.valueCurrency ?? null,\n },\n {\n persistent: true,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n },\n )\n }\n } catch (err) {\n logger.warn('Deal closure event emit failed', { component: 'deals.update', closureEvent, err })\n }\n }\n\n return { dealId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadDealSnapshot(em, result.dealId)\n },\n buildLog: async ({ result, snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as DealSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadDealSnapshot(em, result.dealId)\n return {\n actionLabel: translate('customers.audit.deals.update', 'Update deal'),\n resourceKind: 'customers.deal',\n resourceId: before.deal.id,\n tenantId: before.deal.tenantId,\n organizationId: before.deal.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DealUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: before.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: before.deal.id,\n organizationId: before.deal.organizationId,\n tenantId: before.deal.tenantId,\n title: before.deal.title,\n description: before.deal.description,\n status: before.deal.status,\n pipelineStage: before.deal.pipelineStage,\n pipelineId: before.deal.pipelineId,\n pipelineStageId: before.deal.pipelineStageId,\n valueAmount: before.deal.valueAmount,\n valueCurrency: before.deal.valueCurrency,\n probability: before.deal.probability,\n expectedCloseAt: coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt'),\n ownerUserId: before.deal.ownerUserId,\n source: before.deal.source,\n closureOutcome: before.deal.closureOutcome,\n lossReasonId: before.deal.lossReasonId,\n lossNotes: before.deal.lossNotes,\n })\n em.persist(deal)\n }\n const revertedStageSnapshot = before.deal.pipelineStageId\n ? await loadPipelineStageSnapshot(em, before.deal.pipelineStageId, before.deal.tenantId, before.deal.organizationId)\n : null\n const existingTransition = before.deal.pipelineStageId\n ? before.transitions.find((transition) => transition.stageId === before.deal.pipelineStageId) ?? null\n : null\n const shouldRecordRevertTransition =\n before.deal.pipelineStageId !== (payload?.after?.deal.pipelineStageId ?? null) &&\n !!before.deal.pipelineStageId &&\n !!(revertedStageSnapshot?.pipelineId ?? before.deal.pipelineId ?? existingTransition?.pipelineId) &&\n !!(revertedStageSnapshot?.label ?? before.deal.pipelineStage ?? existingTransition?.stageLabel)\n\n await withAtomicFlush(em, [\n () => {\n deal.title = before.deal.title\n deal.description = before.deal.description\n deal.status = before.deal.status\n deal.pipelineStage = before.deal.pipelineStage\n deal.pipelineId = before.deal.pipelineId\n deal.pipelineStageId = before.deal.pipelineStageId\n deal.valueAmount = before.deal.valueAmount\n deal.valueCurrency = before.deal.valueCurrency\n deal.probability = before.deal.probability\n deal.expectedCloseAt = coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt')\n deal.ownerUserId = before.deal.ownerUserId\n deal.source = before.deal.source\n deal.closureOutcome = before.deal.closureOutcome\n deal.lossReasonId = before.deal.lossReasonId\n deal.lossNotes = before.deal.lossNotes\n },\n async () => {\n // Mirror of the fix applied to the forward `execute` path: persist the scalar\n // mutations on `deal` before any further `em.findOne` (the transition lookup\n // inside `upsertDealStageTransition`) or sync-helper queries run on the same EM.\n // MikroORM v7 silently discards the pending scalar changes if we don't flush here\n // (see SPEC-018), which would make an undo of a kanban stage move silently no-op.\n await em.flush()\n },\n async () => {\n if (!shouldRecordRevertTransition || !before.deal.pipelineStageId) return\n const pipelineId = revertedStageSnapshot?.pipelineId ?? before.deal.pipelineId ?? existingTransition?.pipelineId\n const stageLabel = revertedStageSnapshot?.label ?? before.deal.pipelineStage ?? existingTransition?.stageLabel\n if (!pipelineId || !stageLabel) return\n await upsertDealStageTransition(em, {\n deal,\n pipelineId,\n stageId: before.deal.pipelineStageId,\n stageLabel,\n stageOrder: revertedStageSnapshot?.order ?? existingTransition?.stageOrder ?? 0,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, before.companies),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n },\n}\n\nconst deleteDealCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { dealId: string }> =\n {\n id: 'customers.deals.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Deal id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Deal id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id, deletedAt: null })\n const record = deal ?? null\n if (!record) throw notFound('Deal not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n await deleteDealStageTransitions(em, record)\n await em.nativeDelete(CustomerDealPersonLink, { deal: record })\n await em.nativeDelete(CustomerDealCompanyLink, { deal: record })\n em.remove(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n return { dealId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as DealSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.deals.delete', 'Delete deal'),\n resourceKind: 'customers.deal',\n resourceId: before.deal.id,\n tenantId: before.deal.tenantId,\n organizationId: before.deal.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DealUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: before.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: before.deal.id,\n organizationId: before.deal.organizationId,\n tenantId: before.deal.tenantId,\n title: before.deal.title,\n description: before.deal.description,\n status: before.deal.status,\n pipelineStage: before.deal.pipelineStage,\n pipelineId: before.deal.pipelineId,\n pipelineStageId: before.deal.pipelineStageId,\n valueAmount: before.deal.valueAmount,\n valueCurrency: before.deal.valueCurrency,\n probability: before.deal.probability,\n expectedCloseAt: coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt'),\n ownerUserId: before.deal.ownerUserId,\n source: before.deal.source,\n closureOutcome: before.deal.closureOutcome,\n lossReasonId: before.deal.lossReasonId,\n lossNotes: before.deal.lossNotes,\n })\n em.persist(deal)\n }\n await withAtomicFlush(em, [\n () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, before.companies),\n () => deleteDealStageTransitions(em, deal),\n () => restoreDealStageTransitions(em, deal, before.transitions),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n },\n }\n\nregisterCommand(createDealCommand)\nregisterCommand(updateDealCommand)\nregisterCommand(deleteDealCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n normalizeAuthorUserId,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { runCrudCommandWrite } from '@open-mercato/shared/lib/commands/runCrudCommandWrite'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport {\n CustomerDeal,\n CustomerDealPersonLink,\n CustomerDealCompanyLink,\n CustomerDealStageTransition,\n CustomerPipelineStage,\n} from '../data/entities'\nimport {\n dealCreateSchema,\n dealUpdateSchema,\n type DealCreateInput,\n type DealUpdateInput,\n} from '../data/validators'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n requireCustomerEntity,\n ensureSameScope,\n extractUndoPayload,\n ensureDictionaryEntry,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n type CustomFieldChangeSet,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { CrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport type { CrudIndexerConfig, CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\nimport { findWithDecryption, findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { isMissingDealStageTransitionTable, warnMissingDealStageTransitionTable } from '../lib/dealStageTransitionTable'\nimport {\n dealClosureOutcomeFromStatus,\n loadClosurePipelineStageSnapshot,\n type DealClosureOutcome,\n type PipelineStageSnapshot,\n} from '../lib/closureStage'\nimport { canonicalDealStatus, isClosedDealStatus } from '../lib/dealStatus'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('customers')\n\nconst DEAL_ENTITY_ID = 'customers:customer_deal'\nconst dealCrudIndexer: CrudIndexerConfig<CustomerDeal> = {\n entityType: E.customers.customer_deal,\n}\n\nconst dealCrudEvents: CrudEventsConfig = {\n module: 'customers',\n entity: 'deal',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype DealStageTransitionSnapshot = {\n id: string\n pipelineId: string\n stageId: string\n stageLabel: string\n stageOrder: number\n transitionedAt: Date | string\n transitionedByUserId: string | null\n}\n\nfunction coerceSnapshotDate(value: Date | string | null | undefined, fieldName: string): Date | null {\n if (value === undefined || value === null) return null\n if (value instanceof Date) return value\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) {\n throw new Error(`[internal] Invalid ${fieldName} undo snapshot date: ${value}`)\n }\n return date\n}\n\nfunction coerceRequiredSnapshotDate(value: Date | string, fieldName: string): Date {\n const date = coerceSnapshotDate(value, fieldName)\n if (!date) {\n throw new Error(`[internal] Missing ${fieldName} undo snapshot date`)\n }\n return date\n}\n\nasync function loadPipelineStageSnapshot(\n em: EntityManager,\n pipelineStageId: string,\n tenantId: string,\n organizationId: string,\n): Promise<PipelineStageSnapshot | null> {\n const stage = await findOneWithDecryption(em, CustomerPipelineStage, { id: pipelineStageId }, {}, { tenantId, organizationId })\n if (!stage) return null\n return {\n id: stage.id,\n pipelineId: stage.pipelineId,\n label: stage.label,\n order: stage.order,\n }\n}\n\nfunction resolveRequestedClosureOutcome(input: DealUpdateInput): DealClosureOutcome | null {\n if (input.closureOutcome === 'won' || input.closureOutcome === 'lost') {\n return input.closureOutcome\n }\n // `win` / `lost` are what the UI closure flows persist; `won` / `lost` are the\n // spellings the AI stage tool persists (`loose` before 0.7.1). Both must derive the same\n // closure outcome so every closed deal lands in the pipeline's terminal stage (#5107).\n return dealClosureOutcomeFromStatus(input.status)\n}\n\nasync function resolvePipelineStageValue(\n em: EntityManager,\n pipelineStageId: string,\n tenantId: string,\n organizationId: string,\n): Promise<string | null> {\n const stage = await loadPipelineStageSnapshot(em, pipelineStageId, tenantId, organizationId)\n if (!stage) return null\n const entry = await ensureDictionaryEntry(em, {\n tenantId,\n organizationId,\n kind: 'pipeline_stage',\n value: stage.label,\n })\n return entry?.value ?? stage.label\n}\n\nfunction resolvePipelineAssignment(input: {\n pipelineId?: string | null\n pipelineStageId?: string | null\n stageSnapshot: PipelineStageSnapshot | null\n}): { pipelineId: string | null; pipelineStageId: string | null } {\n const requestedPipelineId = input.pipelineId ?? null\n const requestedPipelineStageId = input.pipelineStageId ?? null\n\n if (requestedPipelineStageId && !input.stageSnapshot) {\n throw new CrudHttpError(400, { error: 'Pipeline stage not found' })\n }\n\n if (\n requestedPipelineId &&\n input.stageSnapshot &&\n input.stageSnapshot.pipelineId !== requestedPipelineId\n ) {\n throw new CrudHttpError(400, {\n error: 'Pipeline stage does not belong to the selected pipeline',\n })\n }\n\n return {\n pipelineId: requestedPipelineId ?? input.stageSnapshot?.pipelineId ?? null,\n pipelineStageId: requestedPipelineStageId,\n }\n}\n\nasync function upsertDealStageTransition(\n em: EntityManager,\n input: {\n deal: CustomerDeal\n pipelineId: string\n stageId: string\n stageLabel: string\n stageOrder: number\n transitionedByUserId: string | null\n transitionedAt?: Date\n },\n): Promise<void> {\n let existing: CustomerDealStageTransition | null = null\n try {\n existing = await findOneWithDecryption(\n em,\n CustomerDealStageTransition,\n { deal: input.deal.id, stageId: input.stageId, deletedAt: null },\n {},\n { tenantId: input.deal.tenantId, organizationId: input.deal.organizationId },\n )\n } catch (error) {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.upsertTransition')\n return\n }\n const transitionedAt = input.transitionedAt ?? new Date()\n if (existing) {\n existing.pipelineId = input.pipelineId\n existing.stageLabel = input.stageLabel\n existing.stageOrder = input.stageOrder\n existing.transitionedAt = transitionedAt\n existing.transitionedByUserId = input.transitionedByUserId\n existing.deletedAt = null\n existing.isActive = true\n return\n }\n\n const transition = em.create(CustomerDealStageTransition, {\n organizationId: input.deal.organizationId,\n tenantId: input.deal.tenantId,\n deal: input.deal,\n pipelineId: input.pipelineId,\n stageId: input.stageId,\n stageLabel: input.stageLabel,\n stageOrder: input.stageOrder,\n transitionedAt,\n transitionedByUserId: input.transitionedByUserId,\n isActive: true,\n })\n em.persist(transition)\n}\n\nasync function deleteDealStageTransitions(em: EntityManager, deal: CustomerDeal): Promise<void> {\n try {\n await em.nativeDelete(CustomerDealStageTransition, { deal: deal.id })\n } catch (error) {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.deleteTransitions')\n }\n}\n\nasync function restoreDealStageTransitions(\n em: EntityManager,\n deal: CustomerDeal,\n transitions: DealStageTransitionSnapshot[],\n): Promise<void> {\n if (!transitions.length) return\n for (const transitionSnapshot of transitions) {\n const transition = em.create(CustomerDealStageTransition, {\n id: transitionSnapshot.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n deal,\n pipelineId: transitionSnapshot.pipelineId,\n stageId: transitionSnapshot.stageId,\n stageLabel: transitionSnapshot.stageLabel,\n stageOrder: transitionSnapshot.stageOrder,\n transitionedAt: coerceRequiredSnapshotDate(transitionSnapshot.transitionedAt, 'transitionedAt'),\n transitionedByUserId: transitionSnapshot.transitionedByUserId,\n isActive: true,\n })\n em.persist(transition)\n }\n}\n\ntype DealSnapshot = {\n deal: {\n id: string\n organizationId: string\n tenantId: string\n title: string\n description: string | null\n status: string\n pipelineStage: string | null\n pipelineId: string | null\n pipelineStageId: string | null\n valueAmount: string | null\n valueCurrency: string | null\n probability: number | null\n expectedCloseAt: Date | string | null\n ownerUserId: string | null\n source: string | null\n closureOutcome: string | null\n lossReasonId: string | null\n lossNotes: string | null\n }\n people: string[]\n primaryPersonEntityId?: string | null\n companies: string[]\n transitions: DealStageTransitionSnapshot[]\n custom?: Record<string, unknown>\n}\n\ntype DealUndoPayload = {\n before?: DealSnapshot | null\n after?: DealSnapshot | null\n}\n\ntype DealChangeMap = Record<string, { from: unknown; to: unknown }> & {\n custom?: CustomFieldChangeSet\n}\n\nasync function loadDealSnapshot(em: EntityManager, id: string): Promise<DealSnapshot | null> {\n const deal = await findOneWithDecryption(em, CustomerDeal, { id, deletedAt: null })\n if (!deal) return null\n const decryptionScope = { tenantId: deal.tenantId ?? null, organizationId: deal.organizationId ?? null }\n const peopleLinks = await findWithDecryption(\n em,\n CustomerDealPersonLink,\n { deal: deal },\n { populate: ['person'] },\n decryptionScope,\n )\n const companyLinks = await findWithDecryption(\n em,\n CustomerDealCompanyLink,\n { deal: deal },\n { populate: ['company'] },\n decryptionScope,\n )\n const transitions = await findWithDecryption(\n em,\n CustomerDealStageTransition,\n { deal: deal.id, deletedAt: null },\n { orderBy: { stageOrder: 'ASC', transitionedAt: 'ASC' } },\n decryptionScope,\n ).catch((error: unknown) => {\n if (!isMissingDealStageTransitionTable(error)) {\n throw error\n }\n warnMissingDealStageTransitionTable('customers.commands.deals.loadSnapshot')\n return [] as CustomerDealStageTransition[]\n })\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n tenantId: deal.tenantId,\n organizationId: deal.organizationId,\n })\n const primaryPerson = peopleLinks.find((link) => link.isPrimary)?.person\n return {\n deal: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n title: deal.title,\n description: deal.description ?? null,\n status: deal.status,\n pipelineStage: deal.pipelineStage ?? null,\n pipelineId: deal.pipelineId ?? null,\n pipelineStageId: deal.pipelineStageId ?? null,\n valueAmount: deal.valueAmount ?? null,\n valueCurrency: deal.valueCurrency ?? null,\n probability: deal.probability ?? null,\n expectedCloseAt: deal.expectedCloseAt ?? null,\n ownerUserId: deal.ownerUserId ?? null,\n source: deal.source ?? null,\n closureOutcome: deal.closureOutcome ?? null,\n lossReasonId: deal.lossReasonId ?? null,\n lossNotes: deal.lossNotes ?? null,\n },\n people: peopleLinks.map((link) =>\n typeof link.person === 'string' ? link.person : link.person.id\n ),\n primaryPersonEntityId:\n typeof primaryPerson === 'string' ? primaryPerson : primaryPerson?.id ?? null,\n companies: companyLinks.map((link) =>\n typeof link.company === 'string' ? link.company : link.company.id\n ),\n transitions: transitions.map((transition) => ({\n id: transition.id,\n pipelineId: transition.pipelineId,\n stageId: transition.stageId,\n stageLabel: transition.stageLabel,\n stageOrder: transition.stageOrder,\n transitionedAt: transition.transitionedAt,\n transitionedByUserId: transition.transitionedByUserId ?? null,\n })),\n custom,\n }\n}\n\nfunction toNumericString(value: number | null | undefined): string | null {\n if (value === undefined || value === null) return null\n return value.toString()\n}\n\nasync function syncDealPeople(\n em: EntityManager,\n deal: CustomerDeal,\n personIds: string[] | undefined | null,\n primaryPersonEntityId?: string | null\n): Promise<void> {\n if (personIds === undefined) {\n if (primaryPersonEntityId === undefined) return\n const links = await em.find(CustomerDealPersonLink, { deal })\n if (primaryPersonEntityId !== null && !links.some((link) => link.person.id === primaryPersonEntityId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate(\n 'customers.errors.primaryPersonMustBeLinked',\n 'Primary person must be linked to the deal',\n ),\n })\n }\n for (const link of links) {\n link.isPrimary = false\n }\n await em.flush()\n if (primaryPersonEntityId !== null) {\n const primaryLink = links.find((link) => link.person.id === primaryPersonEntityId)\n if (primaryLink) primaryLink.isPrimary = true\n }\n return\n }\n const unique = Array.from(new Set(personIds ?? []))\n if (primaryPersonEntityId !== undefined && primaryPersonEntityId !== null && !unique.includes(primaryPersonEntityId)) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(400, {\n error: translate(\n 'customers.errors.primaryPersonMustBeLinked',\n 'Primary person must be linked to the deal',\n ),\n })\n }\n let effectivePrimaryId = primaryPersonEntityId\n if (effectivePrimaryId === undefined) {\n const existingPrimary = await em.findOne(CustomerDealPersonLink, { deal, isPrimary: true })\n effectivePrimaryId = existingPrimary?.person?.id ?? null\n }\n await em.nativeDelete(CustomerDealPersonLink, { deal })\n if (!unique.length) return\n for (const personId of unique) {\n const person = await requireCustomerEntity(em, personId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'person', 'Person not found')\n ensureSameScope(person, deal.organizationId, deal.tenantId)\n const link = em.create(CustomerDealPersonLink, {\n deal,\n person,\n isPrimary: personId === effectivePrimaryId,\n })\n em.persist(link)\n }\n}\n\nasync function syncDealCompanies(\n em: EntityManager,\n deal: CustomerDeal,\n companyIds: string[] | undefined | null\n): Promise<void> {\n if (companyIds === undefined) return\n await em.nativeDelete(CustomerDealCompanyLink, { deal })\n if (!companyIds || !companyIds.length) return\n const unique = Array.from(new Set(companyIds))\n for (const companyId of unique) {\n const company = await requireCustomerEntity(em, companyId, { tenantId: deal.tenantId, organizationId: deal.organizationId }, 'company', 'Company not found')\n ensureSameScope(company, deal.organizationId, deal.tenantId)\n const link = em.create(CustomerDealCompanyLink, {\n deal,\n company,\n })\n em.persist(link)\n }\n}\n\nconst createDealCommand: CommandHandler<DealCreateInput, { dealId: string }> = {\n id: 'customers.deals.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(dealCreateSchema, rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n let deal!: CustomerDeal\n let stageSnapshot: PipelineStageSnapshot | null = null\n let pipelineAssignment: { pipelineId: string | null; pipelineStageId: string | null } = {\n pipelineId: null,\n pipelineStageId: null,\n }\n let resolvedPipelineStageLabel: string | null = null\n await withAtomicFlush(em, [\n async () => {\n stageSnapshot = parsed.pipelineStageId\n ? await loadPipelineStageSnapshot(em, parsed.pipelineStageId, parsed.tenantId, parsed.organizationId)\n : null\n pipelineAssignment = resolvePipelineAssignment({\n pipelineId: parsed.pipelineId,\n pipelineStageId: parsed.pipelineStageId,\n stageSnapshot,\n })\n resolvedPipelineStageLabel = stageSnapshot\n ? (await ensureDictionaryEntry(em, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n kind: 'pipeline_stage',\n value: stageSnapshot.label,\n }))?.value ?? stageSnapshot.label\n : parsed.pipelineStage ?? null\n },\n async () => {\n deal = em.create(CustomerDeal, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n title: parsed.title,\n description: parsed.description ?? null,\n status: parsed.status ?? 'open',\n pipelineStage: resolvedPipelineStageLabel,\n pipelineId: pipelineAssignment.pipelineId,\n pipelineStageId: pipelineAssignment.pipelineStageId,\n valueAmount: toNumericString(parsed.valueAmount),\n valueCurrency: parsed.valueCurrency ?? null,\n probability: parsed.probability ?? null,\n expectedCloseAt: parsed.expectedCloseAt ?? null,\n ownerUserId: parsed.ownerUserId ?? null,\n source: parsed.source ?? null,\n closureOutcome: parsed.closureOutcome ?? null,\n lossReasonId: parsed.lossReasonId ?? null,\n lossNotes: parsed.lossNotes ?? null,\n })\n em.persist(deal)\n await em.flush()\n },\n async () => {\n const snapshot = stageSnapshot\n if (!snapshot) return\n await upsertDealStageTransition(em, {\n deal,\n pipelineId: snapshot.pipelineId,\n stageId: snapshot.id,\n stageLabel: snapshot.label,\n stageOrder: snapshot.order,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, deal, parsed.personIds ?? [], parsed.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, parsed.companyIds ?? []),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: custom,\n notify: false,\n })\n\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n return { dealId: deal.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadDealSnapshot(em, result.dealId)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, result.dealId)\n return {\n actionLabel: translate('customers.audit.deals.create', 'Create deal'),\n resourceKind: 'customers.deal',\n resourceId: result.dealId,\n tenantId: snapshot?.deal.tenantId ?? null,\n organizationId: snapshot?.deal.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const dealId = logEntry?.resourceId\n if (!dealId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id: dealId })\n if (!deal) return\n await deleteDealStageTransitions(em, deal)\n await em.nativeDelete(CustomerDealPersonLink, { deal })\n await em.nativeDelete(CustomerDealCompanyLink, { deal })\n em.remove(deal)\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<DealSnapshot>(logEntry)\n if (!after) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for deal create' })\n }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: after.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: after.deal.id,\n organizationId: after.deal.organizationId,\n tenantId: after.deal.tenantId,\n title: after.deal.title,\n description: after.deal.description,\n status: after.deal.status,\n pipelineStage: after.deal.pipelineStage,\n pipelineId: after.deal.pipelineId,\n pipelineStageId: after.deal.pipelineStageId,\n valueAmount: after.deal.valueAmount,\n valueCurrency: after.deal.valueCurrency,\n probability: after.deal.probability,\n expectedCloseAt: after.deal.expectedCloseAt,\n ownerUserId: after.deal.ownerUserId,\n source: after.deal.source,\n closureOutcome: after.deal.closureOutcome,\n lossReasonId: after.deal.lossReasonId,\n lossNotes: after.deal.lossNotes,\n })\n em.persist(deal)\n }\n const restoredDeal = deal\n await withAtomicFlush(em, [\n () => syncDealPeople(em, restoredDeal, after.people, after.primaryPersonEntityId),\n () => syncDealCompanies(em, restoredDeal, after.companies),\n () => deleteDealStageTransitions(em, restoredDeal),\n () => restoreDealStageTransitions(em, restoredDeal, after.transitions),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: restoredDeal,\n identifiers: {\n id: restoredDeal.id,\n organizationId: restoredDeal.organizationId,\n tenantId: restoredDeal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const restoreValues = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(restoreValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: restoredDeal.id,\n organizationId: restoredDeal.organizationId,\n tenantId: restoredDeal.tenantId,\n values: restoreValues,\n notify: false,\n })\n }\n\n return { dealId: restoredDeal.id }\n },\n}\n\nconst updateDealCommand: CommandHandler<DealUpdateInput, { dealId: string }> = {\n id: 'customers.deals.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(dealUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(dealUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id: parsed.id, deletedAt: null })\n const record = deal ?? null\n if (!record) throw notFound('Deal not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n\n const previousStatus = record.status\n const previousPipelineStageId = record.pipelineStageId ?? null\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n\n let nextStageSnapshot: PipelineStageSnapshot | null = null\n let nextPipelineAssignment: { pipelineId: string | null; pipelineStageId: string | null } = {\n pipelineId: record.pipelineId ?? null,\n pipelineStageId: record.pipelineStageId ?? null,\n }\n let nextPipelineStageLabel: string | null = null\n let resolvedCurrentPipelineStageLabel: string | null = null\n let pipelineStageAssignmentChanged = false\n let requestedClosureOutcome: DealClosureOutcome | null = null\n\n await runCrudCommandWrite({\n ctx,\n em,\n entityId: DEAL_ENTITY_ID,\n action: 'updated',\n scope: { tenantId: record.tenantId, organizationId: record.organizationId },\n customFields: custom,\n events: dealCrudEvents,\n indexer: dealCrudIndexer,\n sideEffect: () => ({\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n }),\n phases: [\n async () => {\n requestedClosureOutcome = resolveRequestedClosureOutcome(parsed)\n const requestedPipelineId =\n parsed.pipelineId !== undefined ? parsed.pipelineId ?? null : record.pipelineId ?? null\n const closureStageSnapshot =\n parsed.pipelineStageId === undefined && requestedClosureOutcome\n ? await loadClosurePipelineStageSnapshot(em, {\n pipelineId: requestedPipelineId,\n closureOutcome: requestedClosureOutcome,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n })\n : null\n pipelineStageAssignmentChanged =\n parsed.pipelineStageId !== undefined || closureStageSnapshot !== null\n const pipelineAssignmentChanged =\n parsed.pipelineId !== undefined || pipelineStageAssignmentChanged\n const requestedPipelineStageId =\n parsed.pipelineStageId !== undefined\n ? parsed.pipelineStageId ?? null\n : closureStageSnapshot?.id ?? record.pipelineStageId ?? null\n\n nextStageSnapshot = closureStageSnapshot ?? (\n requestedPipelineStageId && (pipelineAssignmentChanged || !record.pipelineStage)\n ? await loadPipelineStageSnapshot(em, requestedPipelineStageId, record.tenantId, record.organizationId)\n : null\n )\n if (pipelineAssignmentChanged) {\n nextPipelineAssignment = resolvePipelineAssignment({\n pipelineId: requestedPipelineId,\n pipelineStageId: requestedPipelineStageId,\n stageSnapshot: nextStageSnapshot,\n })\n }\n nextPipelineStageLabel = nextStageSnapshot\n ? (await ensureDictionaryEntry(em, {\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n kind: 'pipeline_stage',\n value: nextStageSnapshot.label,\n }))?.value ?? nextStageSnapshot.label\n : null\n resolvedCurrentPipelineStageLabel =\n !nextStageSnapshot && record.pipelineStageId && (parsed.pipelineStageId !== undefined || !record.pipelineStage)\n ? await resolvePipelineStageValue(em, record.pipelineStageId, record.tenantId, record.organizationId)\n : null\n },\n () => {\n if (parsed.title !== undefined) record.title = parsed.title\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.status !== undefined) record.status = parsed.status ?? record.status\n if (parsed.pipelineStage !== undefined) record.pipelineStage = parsed.pipelineStage ?? null\n if (parsed.pipelineId !== undefined || (pipelineStageAssignmentChanged && nextStageSnapshot)) {\n record.pipelineId = nextPipelineAssignment.pipelineId\n }\n if (pipelineStageAssignmentChanged) record.pipelineStageId = nextPipelineAssignment.pipelineStageId\n\n if (nextPipelineStageLabel && (pipelineStageAssignmentChanged || !record.pipelineStage)) {\n record.pipelineStage = nextPipelineStageLabel\n } else if (resolvedCurrentPipelineStageLabel && (pipelineStageAssignmentChanged || !record.pipelineStage)) {\n record.pipelineStage = resolvedCurrentPipelineStageLabel\n }\n\n if (parsed.valueAmount !== undefined) record.valueAmount = toNumericString(parsed.valueAmount)\n if (parsed.valueCurrency !== undefined) record.valueCurrency = parsed.valueCurrency ?? null\n if (parsed.probability !== undefined) record.probability = parsed.probability ?? null\n if (parsed.expectedCloseAt !== undefined) record.expectedCloseAt = parsed.expectedCloseAt ?? null\n if (parsed.ownerUserId !== undefined) record.ownerUserId = parsed.ownerUserId ?? null\n if (parsed.source !== undefined) record.source = parsed.source ?? null\n if (parsed.closureOutcome !== undefined) record.closureOutcome = parsed.closureOutcome ?? null\n // Derive the outcome only when the status spelling alone drives the closure \u2014\n // the same condition that triggers the terminal-stage move below \u2014 so an\n // explicit non-terminal pipelineStageId never produces a half-closed state.\n else if (requestedClosureOutcome && parsed.pipelineStageId === undefined) {\n record.closureOutcome = requestedClosureOutcome\n } else if (\n parsed.status !== undefined &&\n !requestedClosureOutcome &&\n // `closed` is a seeded dictionary status: saving it is not a reopen, so only\n // a genuinely non-closed status clears stored closure state \u2014 and only when\n // the deal actually carries any (a no-op status echo must not wipe loss data).\n // Canonicalize first: `dealClosureOutcomeFromStatus` above already matches\n // case-insensitively, so matching `closed` exactly would let `Closed` through\n // this guard and null the operator's loss notes.\n !isClosedDealStatus(canonicalDealStatus(parsed.status)) &&\n record.closureOutcome !== null\n ) {\n record.closureOutcome = null\n if (parsed.lossReasonId === undefined) record.lossReasonId = null\n if (parsed.lossNotes === undefined) record.lossNotes = null\n }\n if (parsed.lossReasonId !== undefined) record.lossReasonId = parsed.lossReasonId ?? null\n if (parsed.lossNotes !== undefined) record.lossNotes = parsed.lossNotes ?? null\n },\n async () => {\n // CRITICAL: persist the scalar mutations above before any further `em.findOne` / sync\n // helpers run inside this transaction. MikroORM v7's identity-map silently discards\n // pending scalar changes on `record` if a query (such as the stage-transition lookup\n // inside `upsertDealStageTransition`, or the linked-entity finds inside\n // `syncDealPeople` / `syncDealCompanies`) executes on the same `EntityManager`\n // before we explicitly flush. Without this flush, the entire kanban drag-and-drop\n // returns 200 OK but never actually updates `customer_deals` rows \u2014 the card\n // snaps back to its source lane on the next refetch (see SPEC-018).\n await em.flush()\n },\n async () => {\n const snapshot = nextStageSnapshot\n if (!snapshot) return\n const shouldRecord =\n pipelineStageAssignmentChanged &&\n nextPipelineAssignment.pipelineStageId !== null &&\n nextPipelineAssignment.pipelineStageId !== previousPipelineStageId\n if (!shouldRecord) return\n await upsertDealStageTransition(em, {\n deal: record,\n pipelineId: snapshot.pipelineId,\n stageId: snapshot.id,\n stageLabel: nextPipelineStageLabel ?? snapshot.label,\n stageOrder: snapshot.order,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, record, parsed.personIds, parsed.primaryPersonEntityId),\n () => syncDealCompanies(em, record, parsed.companyIds),\n ],\n })\n\n // Emit a lifecycle event for deal won/lost status changes; the notifications\n // subscriber translates these into recipient notifications. Tenant/organization\n // scope MUST travel in the emit options, not only in the payload: both delivery\n // paths build the subscriber context from `options` alone, so wildcard\n // subscribers (workflow event triggers, business-rules triggers) drop a\n // null-scoped event before trigger matching.\n const newStatus = record.status\n // `loose` stays mapped here for deals written before the 0.7.1 rename.\n const normalizedStatus = newStatus === 'win' ? 'won' : newStatus === 'loose' ? 'lost' : newStatus\n if (previousStatus !== newStatus && (normalizedStatus === 'won' || normalizedStatus === 'lost')) {\n const closureEvent = normalizedStatus === 'won' ? 'customers.deal.won' : 'customers.deal.lost'\n try {\n const eventBus = ctx.container.resolve('eventBus') as { emitEvent(event: string, payload: unknown, options?: unknown): Promise<void> } | undefined\n if (eventBus) {\n await eventBus.emitEvent(\n closureEvent,\n {\n id: record.id,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n ownerUserId: record.ownerUserId ?? null,\n title: record.title,\n valueAmount: record.valueAmount ?? null,\n valueCurrency: record.valueCurrency ?? null,\n },\n {\n persistent: true,\n tenantId: record.tenantId,\n organizationId: record.organizationId,\n },\n )\n }\n } catch (err) {\n logger.warn('Deal closure event emit failed', { component: 'deals.update', closureEvent, err })\n }\n }\n\n return { dealId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadDealSnapshot(em, result.dealId)\n },\n buildLog: async ({ result, snapshots, ctx }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as DealSnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const afterSnapshot = await loadDealSnapshot(em, result.dealId)\n return {\n actionLabel: translate('customers.audit.deals.update', 'Update deal'),\n resourceKind: 'customers.deal',\n resourceId: before.deal.id,\n tenantId: before.deal.tenantId,\n organizationId: before.deal.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DealUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const normalizedTransitionAuthorUserId = normalizeAuthorUserId(null, ctx.auth)\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: before.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: before.deal.id,\n organizationId: before.deal.organizationId,\n tenantId: before.deal.tenantId,\n title: before.deal.title,\n description: before.deal.description,\n status: before.deal.status,\n pipelineStage: before.deal.pipelineStage,\n pipelineId: before.deal.pipelineId,\n pipelineStageId: before.deal.pipelineStageId,\n valueAmount: before.deal.valueAmount,\n valueCurrency: before.deal.valueCurrency,\n probability: before.deal.probability,\n expectedCloseAt: coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt'),\n ownerUserId: before.deal.ownerUserId,\n source: before.deal.source,\n closureOutcome: before.deal.closureOutcome,\n lossReasonId: before.deal.lossReasonId,\n lossNotes: before.deal.lossNotes,\n })\n em.persist(deal)\n }\n const revertedStageSnapshot = before.deal.pipelineStageId\n ? await loadPipelineStageSnapshot(em, before.deal.pipelineStageId, before.deal.tenantId, before.deal.organizationId)\n : null\n const existingTransition = before.deal.pipelineStageId\n ? before.transitions.find((transition) => transition.stageId === before.deal.pipelineStageId) ?? null\n : null\n const shouldRecordRevertTransition =\n before.deal.pipelineStageId !== (payload?.after?.deal.pipelineStageId ?? null) &&\n !!before.deal.pipelineStageId &&\n !!(revertedStageSnapshot?.pipelineId ?? before.deal.pipelineId ?? existingTransition?.pipelineId) &&\n !!(revertedStageSnapshot?.label ?? before.deal.pipelineStage ?? existingTransition?.stageLabel)\n\n await withAtomicFlush(em, [\n () => {\n deal.title = before.deal.title\n deal.description = before.deal.description\n deal.status = before.deal.status\n deal.pipelineStage = before.deal.pipelineStage\n deal.pipelineId = before.deal.pipelineId\n deal.pipelineStageId = before.deal.pipelineStageId\n deal.valueAmount = before.deal.valueAmount\n deal.valueCurrency = before.deal.valueCurrency\n deal.probability = before.deal.probability\n deal.expectedCloseAt = coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt')\n deal.ownerUserId = before.deal.ownerUserId\n deal.source = before.deal.source\n deal.closureOutcome = before.deal.closureOutcome\n deal.lossReasonId = before.deal.lossReasonId\n deal.lossNotes = before.deal.lossNotes\n },\n async () => {\n // Mirror of the fix applied to the forward `execute` path: persist the scalar\n // mutations on `deal` before any further `em.findOne` (the transition lookup\n // inside `upsertDealStageTransition`) or sync-helper queries run on the same EM.\n // MikroORM v7 silently discards the pending scalar changes if we don't flush here\n // (see SPEC-018), which would make an undo of a kanban stage move silently no-op.\n await em.flush()\n },\n async () => {\n if (!shouldRecordRevertTransition || !before.deal.pipelineStageId) return\n const pipelineId = revertedStageSnapshot?.pipelineId ?? before.deal.pipelineId ?? existingTransition?.pipelineId\n const stageLabel = revertedStageSnapshot?.label ?? before.deal.pipelineStage ?? existingTransition?.stageLabel\n if (!pipelineId || !stageLabel) return\n await upsertDealStageTransition(em, {\n deal,\n pipelineId,\n stageId: before.deal.pipelineStageId,\n stageLabel,\n stageOrder: revertedStageSnapshot?.order ?? existingTransition?.stageOrder ?? 0,\n transitionedByUserId: normalizedTransitionAuthorUserId,\n })\n },\n () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, before.companies),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, payload?.after?.custom)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n },\n}\n\nconst deleteDealCommand: CommandHandler<{ body?: Record<string, unknown>; query?: Record<string, unknown> }, { dealId: string }> =\n {\n id: 'customers.deals.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Deal id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadDealSnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Deal id required')\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const deal = await findOneWithDecryption(em, CustomerDeal, { id, deletedAt: null })\n const record = deal ?? null\n if (!record) throw notFound('Deal not found')\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n await deleteDealStageTransitions(em, record)\n await em.nativeDelete(CustomerDealPersonLink, { deal: record })\n await em.nativeDelete(CustomerDealCompanyLink, { deal: record })\n em.remove(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n return { dealId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as DealSnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('customers.audit.deals.delete', 'Delete deal'),\n resourceKind: 'customers.deal',\n resourceId: before.deal.id,\n tenantId: before.deal.tenantId,\n organizationId: before.deal.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies DealUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<DealUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let deal = await findOneWithDecryption(em, CustomerDeal, { id: before.deal.id })\n if (!deal) {\n deal = em.create(CustomerDeal, {\n id: before.deal.id,\n organizationId: before.deal.organizationId,\n tenantId: before.deal.tenantId,\n title: before.deal.title,\n description: before.deal.description,\n status: before.deal.status,\n pipelineStage: before.deal.pipelineStage,\n pipelineId: before.deal.pipelineId,\n pipelineStageId: before.deal.pipelineStageId,\n valueAmount: before.deal.valueAmount,\n valueCurrency: before.deal.valueCurrency,\n probability: before.deal.probability,\n expectedCloseAt: coerceSnapshotDate(before.deal.expectedCloseAt, 'expectedCloseAt'),\n ownerUserId: before.deal.ownerUserId,\n source: before.deal.source,\n closureOutcome: before.deal.closureOutcome,\n lossReasonId: before.deal.lossReasonId,\n lossNotes: before.deal.lossNotes,\n })\n em.persist(deal)\n }\n await withAtomicFlush(em, [\n () => syncDealPeople(em, deal, before.people, before.primaryPersonEntityId),\n () => syncDealCompanies(em, deal, before.companies),\n () => deleteDealStageTransitions(em, deal),\n () => restoreDealStageTransitions(em, deal, before.transitions),\n ], { transaction: true })\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: deal,\n identifiers: {\n id: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n },\n indexer: dealCrudIndexer,\n events: dealCrudEvents,\n })\n\n const resetValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(resetValues).length) {\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: DEAL_ENTITY_ID,\n recordId: deal.id,\n organizationId: deal.organizationId,\n tenantId: deal.tenantId,\n values: resetValues,\n notify: false,\n })\n }\n },\n }\n\nregisterCommand(createDealCommand)\nregisterCommand(updateDealCommand)\nregisterCommand(deleteDealCommand)\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,uBAAuB;AAEhC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,2BAA2B;AACpC,SAAS,2BAA2B;AAGpC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,2BAA2B;AACpC;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AACP,SAAS,eAAe,gBAAgB;AAExC,SAAS,SAAS;AAClB,SAAS,oBAAoB,6BAA6B;AAC1D,SAAS,mCAAmC,2CAA2C;AACvF;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,qBAAqB,0BAA0B;AACxD,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,WAAW;AAEvC,MAAM,iBAAiB;AACvB,MAAM,kBAAmD;AAAA,EACvD,YAAY,EAAE,UAAU;AAC1B;AAEA,MAAM,iBAAmC;AAAA,EACvC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,cAAc,CAAC,SAAS;AAAA,IACtB,IAAI,IAAI,YAAY;AAAA,IACpB,gBAAgB,IAAI,YAAY;AAAA,IAChC,UAAU,IAAI,YAAY;AAAA,EAC5B;AACF;AAYA,SAAS,mBAAmB,OAAyC,WAAgC;AACnG,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,MAAI,iBAAiB,KAAM,QAAO;AAClC,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,GAAG;AAChC,UAAM,IAAI,MAAM,sBAAsB,SAAS,wBAAwB,KAAK,EAAE;AAAA,EAChF;AACA,SAAO;AACT;AAEA,SAAS,2BAA2B,OAAsB,WAAyB;AACjF,QAAM,OAAO,mBAAmB,OAAO,SAAS;AAChD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,MAAM,sBAAsB,SAAS,qBAAqB;AAAA,EACtE;AACA,SAAO;AACT;AAEA,eAAe,0BACb,IACA,iBACA,UACA,gBACuC;AACvC,QAAM,QAAQ,MAAM,sBAAsB,IAAI,uBAAuB,EAAE,IAAI,gBAAgB,GAAG,CAAC,GAAG,EAAE,UAAU,eAAe,CAAC;AAC9H,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,OAAO,MAAM;AAAA,IACb,OAAO,MAAM;AAAA,EACf;AACF;AAEA,SAAS,+BAA+B,OAAmD;AACzF,MAAI,MAAM,mBAAmB,SAAS,MAAM,mBAAmB,QAAQ;AACrE,WAAO,MAAM;AAAA,EACf;AAIA,SAAO,6BAA6B,MAAM,MAAM;AAClD;AAEA,eAAe,0BACb,IACA,iBACA,UACA,gBACwB;AACxB,QAAM,QAAQ,MAAM,0BAA0B,IAAI,iBAAiB,UAAU,cAAc;AAC3F,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAQ,MAAM,sBAAsB,IAAI;AAAA,IAC5C;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,OAAO,MAAM;AAAA,EACf,CAAC;AACD,SAAO,OAAO,SAAS,MAAM;AAC/B;AAEA,SAAS,0BAA0B,OAI+B;AAChE,QAAM,sBAAsB,MAAM,cAAc;AAChD,QAAM,2BAA2B,MAAM,mBAAmB;AAE1D,MAAI,4BAA4B,CAAC,MAAM,eAAe;AACpD,UAAM,IAAI,cAAc,KAAK,EAAE,OAAO,2BAA2B,CAAC;AAAA,EACpE;AAEA,MACE,uBACA,MAAM,iBACN,MAAM,cAAc,eAAe,qBACnC;AACA,UAAM,IAAI,cAAc,KAAK;AAAA,MAC3B,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,YAAY,uBAAuB,MAAM,eAAe,cAAc;AAAA,IACtE,iBAAiB;AAAA,EACnB;AACF;AAEA,eAAe,0BACb,IACA,OASe;AACf,MAAI,WAA+C;AACnD,MAAI;AACF,eAAW,MAAM;AAAA,MACf;AAAA,MACA;AAAA,MACA,EAAE,MAAM,MAAM,KAAK,IAAI,SAAS,MAAM,SAAS,WAAW,KAAK;AAAA,MAC/D,CAAC;AAAA,MACD,EAAE,UAAU,MAAM,KAAK,UAAU,gBAAgB,MAAM,KAAK,eAAe;AAAA,IAC7E;AAAA,EACF,SAAS,OAAO;AACd,QAAI,CAAC,kCAAkC,KAAK,GAAG;AAC7C,YAAM;AAAA,IACR;AACA,wCAAoC,2CAA2C;AAC/E;AAAA,EACF;AACA,QAAM,iBAAiB,MAAM,kBAAkB,oBAAI,KAAK;AACxD,MAAI,UAAU;AACZ,aAAS,aAAa,MAAM;AAC5B,aAAS,aAAa,MAAM;AAC5B,aAAS,aAAa,MAAM;AAC5B,aAAS,iBAAiB;AAC1B,aAAS,uBAAuB,MAAM;AACtC,aAAS,YAAY;AACrB,aAAS,WAAW;AACpB;AAAA,EACF;AAEA,QAAM,aAAa,GAAG,OAAO,6BAA6B;AAAA,IACxD,gBAAgB,MAAM,KAAK;AAAA,IAC3B,UAAU,MAAM,KAAK;AAAA,IACrB,MAAM,MAAM;AAAA,IACZ,YAAY,MAAM;AAAA,IAClB,SAAS,MAAM;AAAA,IACf,YAAY,MAAM;AAAA,IAClB,YAAY,MAAM;AAAA,IAClB;AAAA,IACA,sBAAsB,MAAM;AAAA,IAC5B,UAAU;AAAA,EACZ,CAAC;AACD,KAAG,QAAQ,UAAU;AACvB;AAEA,eAAe,2BAA2B,IAAmB,MAAmC;AAC9F,MAAI;AACF,UAAM,GAAG,aAAa,6BAA6B,EAAE,MAAM,KAAK,GAAG,CAAC;AAAA,EACtE,SAAS,OAAO;AACd,QAAI,CAAC,kCAAkC,KAAK,GAAG;AAC7C,YAAM;AAAA,IACR;AACA,wCAAoC,4CAA4C;AAAA,EAClF;AACF;AAEA,eAAe,4BACb,IACA,MACA,aACe;AACf,MAAI,CAAC,YAAY,OAAQ;AACzB,aAAW,sBAAsB,aAAa;AAC5C,UAAM,aAAa,GAAG,OAAO,6BAA6B;AAAA,MACxD,IAAI,mBAAmB;AAAA,MACvB,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,MACf;AAAA,MACA,YAAY,mBAAmB;AAAA,MAC/B,SAAS,mBAAmB;AAAA,MAC5B,YAAY,mBAAmB;AAAA,MAC/B,YAAY,mBAAmB;AAAA,MAC/B,gBAAgB,2BAA2B,mBAAmB,gBAAgB,gBAAgB;AAAA,MAC9F,sBAAsB,mBAAmB;AAAA,MACzC,UAAU;AAAA,IACZ,CAAC;AACD,OAAG,QAAQ,UAAU;AAAA,EACvB;AACF;AAuCA,eAAe,iBAAiB,IAAmB,IAA0C;AAC3F,QAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,WAAW,KAAK,CAAC;AAClF,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,kBAAkB,EAAE,UAAU,KAAK,YAAY,MAAM,gBAAgB,KAAK,kBAAkB,KAAK;AACvG,QAAM,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,IACA,EAAE,KAAW;AAAA,IACb,EAAE,UAAU,CAAC,QAAQ,EAAE;AAAA,IACvB;AAAA,EACF;AACA,QAAM,eAAe,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA,EAAE,KAAW;AAAA,IACb,EAAE,UAAU,CAAC,SAAS,EAAE;AAAA,IACxB;AAAA,EACF;AACA,QAAM,cAAc,MAAM;AAAA,IACxB;AAAA,IACA;AAAA,IACA,EAAE,MAAM,KAAK,IAAI,WAAW,KAAK;AAAA,IACjC,EAAE,SAAS,EAAE,YAAY,OAAO,gBAAgB,MAAM,EAAE;AAAA,IACxD;AAAA,EACF,EAAE,MAAM,CAAC,UAAmB;AAC1B,QAAI,CAAC,kCAAkC,KAAK,GAAG;AAC7C,YAAM;AAAA,IACR;AACA,wCAAoC,uCAAuC;AAC3E,WAAO,CAAC;AAAA,EACV,CAAC;AACD,QAAM,SAAS,MAAM,wBAAwB,IAAI;AAAA,IAC/C,UAAU;AAAA,IACV,UAAU,KAAK;AAAA,IACf,UAAU,KAAK;AAAA,IACf,gBAAgB,KAAK;AAAA,EACvB,CAAC;AACD,QAAM,gBAAgB,YAAY,KAAK,CAAC,SAAS,KAAK,SAAS,GAAG;AAClE,SAAO;AAAA,IACL,MAAM;AAAA,MACJ,IAAI,KAAK;AAAA,MACT,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,aAAa,KAAK,eAAe;AAAA,MACjC,QAAQ,KAAK;AAAA,MACb,eAAe,KAAK,iBAAiB;AAAA,MACrC,YAAY,KAAK,cAAc;AAAA,MAC/B,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,aAAa,KAAK,eAAe;AAAA,MACjC,eAAe,KAAK,iBAAiB;AAAA,MACrC,aAAa,KAAK,eAAe;AAAA,MACjC,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,aAAa,KAAK,eAAe;AAAA,MACjC,QAAQ,KAAK,UAAU;AAAA,MACvB,gBAAgB,KAAK,kBAAkB;AAAA,MACvC,cAAc,KAAK,gBAAgB;AAAA,MACnC,WAAW,KAAK,aAAa;AAAA,IAC/B;AAAA,IACA,QAAQ,YAAY;AAAA,MAAI,CAAC,SACvB,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS,KAAK,OAAO;AAAA,IAC9D;AAAA,IACA,uBACE,OAAO,kBAAkB,WAAW,gBAAgB,eAAe,MAAM;AAAA,IAC3E,WAAW,aAAa;AAAA,MAAI,CAAC,SAC3B,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,KAAK,QAAQ;AAAA,IACjE;AAAA,IACA,aAAa,YAAY,IAAI,CAAC,gBAAgB;AAAA,MAC5C,IAAI,WAAW;AAAA,MACf,YAAY,WAAW;AAAA,MACvB,SAAS,WAAW;AAAA,MACpB,YAAY,WAAW;AAAA,MACvB,YAAY,WAAW;AAAA,MACvB,gBAAgB,WAAW;AAAA,MAC3B,sBAAsB,WAAW,wBAAwB;AAAA,IAC3D,EAAE;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,OAAiD;AACxE,MAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,SAAO,MAAM,SAAS;AACxB;AAEA,eAAe,eACb,IACA,MACA,WACA,uBACe;AACf,MAAI,cAAc,QAAW;AAC3B,QAAI,0BAA0B,OAAW;AACzC,UAAM,QAAQ,MAAM,GAAG,KAAK,wBAAwB,EAAE,KAAK,CAAC;AAC5D,QAAI,0BAA0B,QAAQ,CAAC,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,OAAO,qBAAqB,GAAG;AACrG,YAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,YAAM,IAAI,cAAc,KAAK;AAAA,QAC3B,OAAO;AAAA,UACL;AAAA,UACA;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AACA,eAAW,QAAQ,OAAO;AACxB,WAAK,YAAY;AAAA,IACnB;AACA,UAAM,GAAG,MAAM;AACf,QAAI,0BAA0B,MAAM;AAClC,YAAM,cAAc,MAAM,KAAK,CAAC,SAAS,KAAK,OAAO,OAAO,qBAAqB;AACjF,UAAI,YAAa,aAAY,YAAY;AAAA,IAC3C;AACA;AAAA,EACF;AACA,QAAM,SAAS,MAAM,KAAK,IAAI,IAAI,aAAa,CAAC,CAAC,CAAC;AAClD,MAAI,0BAA0B,UAAa,0BAA0B,QAAQ,CAAC,OAAO,SAAS,qBAAqB,GAAG;AACpH,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,IAAI,cAAc,KAAK;AAAA,MAC3B,OAAO;AAAA,QACL;AAAA,QACA;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AACA,MAAI,qBAAqB;AACzB,MAAI,uBAAuB,QAAW;AACpC,UAAM,kBAAkB,MAAM,GAAG,QAAQ,wBAAwB,EAAE,MAAM,WAAW,KAAK,CAAC;AAC1F,yBAAqB,iBAAiB,QAAQ,MAAM;AAAA,EACtD;AACA,QAAM,GAAG,aAAa,wBAAwB,EAAE,KAAK,CAAC;AACtD,MAAI,CAAC,OAAO,OAAQ;AACpB,aAAW,YAAY,QAAQ;AAC7B,UAAM,SAAS,MAAM,sBAAsB,IAAI,UAAU,EAAE,UAAU,KAAK,UAAU,gBAAgB,KAAK,eAAe,GAAG,UAAU,kBAAkB;AACvJ,oBAAgB,QAAQ,KAAK,gBAAgB,KAAK,QAAQ;AAC1D,UAAM,OAAO,GAAG,OAAO,wBAAwB;AAAA,MAC7C;AAAA,MACA;AAAA,MACA,WAAW,aAAa;AAAA,IAC1B,CAAC;AACD,OAAG,QAAQ,IAAI;AAAA,EACjB;AACF;AAEA,eAAe,kBACb,IACA,MACA,YACe;AACf,MAAI,eAAe,OAAW;AAC9B,QAAM,GAAG,aAAa,yBAAyB,EAAE,KAAK,CAAC;AACvD,MAAI,CAAC,cAAc,CAAC,WAAW,OAAQ;AACvC,QAAM,SAAS,MAAM,KAAK,IAAI,IAAI,UAAU,CAAC;AAC7C,aAAW,aAAa,QAAQ;AAC9B,UAAM,UAAU,MAAM,sBAAsB,IAAI,WAAW,EAAE,UAAU,KAAK,UAAU,gBAAgB,KAAK,eAAe,GAAG,WAAW,mBAAmB;AAC3J,oBAAgB,SAAS,KAAK,gBAAgB,KAAK,QAAQ;AAC3D,UAAM,OAAO,GAAG,OAAO,yBAAyB;AAAA,MAC9C;AAAA,MACA;AAAA,IACF,CAAC;AACD,OAAG,QAAQ,IAAI;AAAA,EACjB;AACF;AAEA,MAAM,oBAAyE;AAAA,EAC7E,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI,sBAAsB,kBAAkB,QAAQ;AAC3E,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,mCAAmC,sBAAsB,MAAM,IAAI,IAAI;AAC7E,QAAI;AACJ,QAAI,gBAA8C;AAClD,QAAI,qBAAoF;AAAA,MACtF,YAAY;AAAA,MACZ,iBAAiB;AAAA,IACnB;AACA,QAAI,6BAA4C;AAChD,UAAM,gBAAgB,IAAI;AAAA,MACxB,YAAY;AACV,wBAAgB,OAAO,kBACnB,MAAM,0BAA0B,IAAI,OAAO,iBAAiB,OAAO,UAAU,OAAO,cAAc,IAClG;AACJ,6BAAqB,0BAA0B;AAAA,UAC7C,YAAY,OAAO;AAAA,UACnB,iBAAiB,OAAO;AAAA,UACxB;AAAA,QACF,CAAC;AACD,qCAA6B,iBACxB,MAAM,sBAAsB,IAAI;AAAA,UACjC,UAAU,OAAO;AAAA,UACjB,gBAAgB,OAAO;AAAA,UACvB,MAAM;AAAA,UACN,OAAO,cAAc;AAAA,QACvB,CAAC,IAAI,SAAS,cAAc,QAC1B,OAAO,iBAAiB;AAAA,MAC9B;AAAA,MACA,YAAY;AACV,eAAO,GAAG,OAAO,cAAc;AAAA,UAC7B,gBAAgB,OAAO;AAAA,UACvB,UAAU,OAAO;AAAA,UACjB,OAAO,OAAO;AAAA,UACd,aAAa,OAAO,eAAe;AAAA,UACnC,QAAQ,OAAO,UAAU;AAAA,UACzB,eAAe;AAAA,UACf,YAAY,mBAAmB;AAAA,UAC/B,iBAAiB,mBAAmB;AAAA,UACpC,aAAa,gBAAgB,OAAO,WAAW;AAAA,UAC/C,eAAe,OAAO,iBAAiB;AAAA,UACvC,aAAa,OAAO,eAAe;AAAA,UACnC,iBAAiB,OAAO,mBAAmB;AAAA,UAC3C,aAAa,OAAO,eAAe;AAAA,UACnC,QAAQ,OAAO,UAAU;AAAA,UACzB,gBAAgB,OAAO,kBAAkB;AAAA,UACzC,cAAc,OAAO,gBAAgB;AAAA,UACrC,WAAW,OAAO,aAAa;AAAA,QACjC,CAAC;AACD,WAAG,QAAQ,IAAI;AACf,cAAM,GAAG,MAAM;AAAA,MACjB;AAAA,MACA,YAAY;AACV,cAAM,WAAW;AACjB,YAAI,CAAC,SAAU;AACf,cAAM,0BAA0B,IAAI;AAAA,UAClC;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,SAAS,SAAS;AAAA,UAClB,YAAY,SAAS;AAAA,UACrB,YAAY,SAAS;AAAA,UACrB,sBAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,MACA,MAAM,eAAe,IAAI,MAAM,OAAO,aAAa,CAAC,GAAG,OAAO,qBAAqB;AAAA,MACnF,MAAM,kBAAkB,IAAI,MAAM,OAAO,cAAc,CAAC,CAAC;AAAA,IAC3D,GAAG,EAAE,aAAa,KAAK,CAAC;AAExB,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,qBAAqB;AAAA,MACzB,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,UAAU,KAAK;AAAA,MACf,gBAAgB,KAAK;AAAA,MACrB,UAAU,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,KAAK;AAAA,QACT,gBAAgB,KAAK;AAAA,QACrB,UAAU,KAAK;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAED,WAAO,EAAE,QAAQ,KAAK,GAAG;AAAA,EAC3B;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,MAAM,iBAAiB,IAAI,OAAO,MAAM;AAAA,EACjD;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,IAAI,MAAM;AACnC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,WAAW,MAAM,iBAAiB,IAAI,OAAO,MAAM;AACzD,WAAO;AAAA,MACL,aAAa,UAAU,gCAAgC,aAAa;AAAA,MACpE,cAAc;AAAA,MACd,YAAY,OAAO;AAAA,MACnB,UAAU,UAAU,KAAK,YAAY;AAAA,MACrC,gBAAgB,UAAU,KAAK,kBAAkB;AAAA,MACjD,eAAe,YAAY;AAAA,MAC3B,SAAS;AAAA,QACP,MAAM;AAAA,UACJ,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,OAAO,CAAC;AACzE,QAAI,CAAC,KAAM;AACX,UAAM,2BAA2B,IAAI,IAAI;AACzC,UAAM,GAAG,aAAa,wBAAwB,EAAE,KAAK,CAAC;AACtD,UAAM,GAAG,aAAa,yBAAyB,EAAE,KAAK,CAAC;AACvD,OAAG,OAAO,IAAI;AACd,UAAM,GAAG,MAAM;AAAA,EACjB;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,QAAQ,oBAAkC,QAAQ;AACxD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,cAAc,KAAK,EAAE,OAAO,uDAAuD,CAAC;AAAA,IAChG;AACA,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,MAAM,KAAK,GAAG,CAAC;AAC9E,QAAI,CAAC,MAAM;AACT,aAAO,GAAG,OAAO,cAAc;AAAA,QAC7B,IAAI,MAAM,KAAK;AAAA,QACf,gBAAgB,MAAM,KAAK;AAAA,QAC3B,UAAU,MAAM,KAAK;AAAA,QACrB,OAAO,MAAM,KAAK;AAAA,QAClB,aAAa,MAAM,KAAK;AAAA,QACxB,QAAQ,MAAM,KAAK;AAAA,QACnB,eAAe,MAAM,KAAK;AAAA,QAC1B,YAAY,MAAM,KAAK;AAAA,QACvB,iBAAiB,MAAM,KAAK;AAAA,QAC5B,aAAa,MAAM,KAAK;AAAA,QACxB,eAAe,MAAM,KAAK;AAAA,QAC1B,aAAa,MAAM,KAAK;AAAA,QACxB,iBAAiB,MAAM,KAAK;AAAA,QAC5B,aAAa,MAAM,KAAK;AAAA,QACxB,QAAQ,MAAM,KAAK;AAAA,QACnB,gBAAgB,MAAM,KAAK;AAAA,QAC3B,cAAc,MAAM,KAAK;AAAA,QACzB,WAAW,MAAM,KAAK;AAAA,MACxB,CAAC;AACD,SAAG,QAAQ,IAAI;AAAA,IACjB;AACA,UAAM,eAAe;AACrB,UAAM,gBAAgB,IAAI;AAAA,MACxB,MAAM,eAAe,IAAI,cAAc,MAAM,QAAQ,MAAM,qBAAqB;AAAA,MAChF,MAAM,kBAAkB,IAAI,cAAc,MAAM,SAAS;AAAA,MACzD,MAAM,2BAA2B,IAAI,YAAY;AAAA,MACjD,MAAM,4BAA4B,IAAI,cAAc,MAAM,WAAW;AAAA,IACvE,GAAG,EAAE,aAAa,KAAK,CAAC;AAExB,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,aAAa;AAAA,QACjB,gBAAgB,aAAa;AAAA,QAC7B,UAAU,aAAa;AAAA,MACzB;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,gBAAgB,yBAAyB,MAAM,QAAQ,MAAS;AACtE,QAAI,OAAO,KAAK,aAAa,EAAE,QAAQ;AACrC,YAAM,qBAAqB;AAAA,QACzB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU,aAAa;AAAA,QACvB,gBAAgB,aAAa;AAAA,QAC7B,UAAU,aAAa;AAAA,QACvB,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAEA,WAAO,EAAE,QAAQ,aAAa,GAAG;AAAA,EACnC;AACF;AAEA,MAAM,oBAAyE;AAAA,EAC7E,IAAI;AAAA,EACJ,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,OAAO,IAAI,sBAAsB,kBAAkB,QAAQ;AACnE,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,WAAW,MAAM,iBAAiB,IAAI,OAAO,EAAE;AACrD,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,UAAU,KAAK;AAC3B,UAAM,EAAE,QAAQ,OAAO,IAAI,sBAAsB,kBAAkB,QAAQ;AAC3E,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,OAAO,IAAI,WAAW,KAAK,CAAC;AAC7F,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,OAAQ,OAAM,SAAS,gBAAgB;AAC5C,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAElD,UAAM,iBAAiB,OAAO;AAC9B,UAAM,0BAA0B,OAAO,mBAAmB;AAC1D,UAAM,mCAAmC,sBAAsB,MAAM,IAAI,IAAI;AAE7E,QAAI,oBAAkD;AACtD,QAAI,yBAAwF;AAAA,MAC1F,YAAY,OAAO,cAAc;AAAA,MACjC,iBAAiB,OAAO,mBAAmB;AAAA,IAC7C;AACA,QAAI,yBAAwC;AAC5C,QAAI,oCAAmD;AACvD,QAAI,iCAAiC;AACrC,QAAI,0BAAqD;AAEzD,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,OAAO,EAAE,UAAU,OAAO,UAAU,gBAAgB,OAAO,eAAe;AAAA,MAC1E,cAAc;AAAA,MACd,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY,OAAO;AAAA,QACjB,QAAQ;AAAA,QACR,aAAa;AAAA,UACX,IAAI,OAAO;AAAA,UACX,gBAAgB,OAAO;AAAA,UACvB,UAAU,OAAO;AAAA,QACnB;AAAA,MACF;AAAA,MACA,QAAQ;AAAA,QACN,YAAY;AACV,oCAA0B,+BAA+B,MAAM;AAC/D,gBAAM,sBACJ,OAAO,eAAe,SAAY,OAAO,cAAc,OAAO,OAAO,cAAc;AACrF,gBAAM,uBACJ,OAAO,oBAAoB,UAAa,0BACpC,MAAM,iCAAiC,IAAI;AAAA,YAC3C,YAAY;AAAA,YACZ,gBAAgB;AAAA,YAChB,UAAU,OAAO;AAAA,YACjB,gBAAgB,OAAO;AAAA,UACzB,CAAC,IACC;AACN,2CACE,OAAO,oBAAoB,UAAa,yBAAyB;AACnE,gBAAM,4BACJ,OAAO,eAAe,UAAa;AACrC,gBAAM,2BACJ,OAAO,oBAAoB,SACvB,OAAO,mBAAmB,OAC1B,sBAAsB,MAAM,OAAO,mBAAmB;AAE5D,8BAAoB,yBAClB,6BAA6B,6BAA6B,CAAC,OAAO,iBAC9D,MAAM,0BAA0B,IAAI,0BAA0B,OAAO,UAAU,OAAO,cAAc,IACpG;AAEN,cAAI,2BAA2B;AAC7B,qCAAyB,0BAA0B;AAAA,cACjD,YAAY;AAAA,cACZ,iBAAiB;AAAA,cACjB,eAAe;AAAA,YACjB,CAAC;AAAA,UACH;AACA,mCAAyB,qBACpB,MAAM,sBAAsB,IAAI;AAAA,YACjC,UAAU,OAAO;AAAA,YACjB,gBAAgB,OAAO;AAAA,YACvB,MAAM;AAAA,YACN,OAAO,kBAAkB;AAAA,UAC3B,CAAC,IAAI,SAAS,kBAAkB,QAC9B;AACJ,8CACE,CAAC,qBAAqB,OAAO,oBAAoB,OAAO,oBAAoB,UAAa,CAAC,OAAO,iBAC7F,MAAM,0BAA0B,IAAI,OAAO,iBAAiB,OAAO,UAAU,OAAO,cAAc,IAClG;AAAA,QACR;AAAA,QACA,MAAM;AACJ,cAAI,OAAO,UAAU,OAAW,QAAO,QAAQ,OAAO;AACtD,cAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,cAAI,OAAO,WAAW,OAAW,QAAO,SAAS,OAAO,UAAU,OAAO;AACzE,cAAI,OAAO,kBAAkB,OAAW,QAAO,gBAAgB,OAAO,iBAAiB;AACvF,cAAI,OAAO,eAAe,UAAc,kCAAkC,mBAAoB;AAC5F,mBAAO,aAAa,uBAAuB;AAAA,UAC7C;AACA,cAAI,+BAAgC,QAAO,kBAAkB,uBAAuB;AAEpF,cAAI,2BAA2B,kCAAkC,CAAC,OAAO,gBAAgB;AACvF,mBAAO,gBAAgB;AAAA,UACzB,WAAW,sCAAsC,kCAAkC,CAAC,OAAO,gBAAgB;AACzG,mBAAO,gBAAgB;AAAA,UACzB;AAEA,cAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,gBAAgB,OAAO,WAAW;AAC7F,cAAI,OAAO,kBAAkB,OAAW,QAAO,gBAAgB,OAAO,iBAAiB;AACvF,cAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,cAAI,OAAO,oBAAoB,OAAW,QAAO,kBAAkB,OAAO,mBAAmB;AAC7F,cAAI,OAAO,gBAAgB,OAAW,QAAO,cAAc,OAAO,eAAe;AACjF,cAAI,OAAO,WAAW,OAAW,QAAO,SAAS,OAAO,UAAU;AAClE,cAAI,OAAO,mBAAmB,OAAW,QAAO,iBAAiB,OAAO,kBAAkB;AAAA,mBAIjF,2BAA2B,OAAO,oBAAoB,QAAW;AACxE,mBAAO,iBAAiB;AAAA,UAC1B,WACE,OAAO,WAAW,UAClB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAOD,CAAC,mBAAmB,oBAAoB,OAAO,MAAM,CAAC,KACtD,OAAO,mBAAmB,MAC1B;AACA,mBAAO,iBAAiB;AACxB,gBAAI,OAAO,iBAAiB,OAAW,QAAO,eAAe;AAC7D,gBAAI,OAAO,cAAc,OAAW,QAAO,YAAY;AAAA,UACzD;AACA,cAAI,OAAO,iBAAiB,OAAW,QAAO,eAAe,OAAO,gBAAgB;AACpF,cAAI,OAAO,cAAc,OAAW,QAAO,YAAY,OAAO,aAAa;AAAA,QAC7E;AAAA,QACA,YAAY;AASV,gBAAM,GAAG,MAAM;AAAA,QACjB;AAAA,QACA,YAAY;AACV,gBAAM,WAAW;AACjB,cAAI,CAAC,SAAU;AACf,gBAAM,eACJ,kCACA,uBAAuB,oBAAoB,QAC3C,uBAAuB,oBAAoB;AAC7C,cAAI,CAAC,aAAc;AACnB,gBAAM,0BAA0B,IAAI;AAAA,YAClC,MAAM;AAAA,YACN,YAAY,SAAS;AAAA,YACrB,SAAS,SAAS;AAAA,YAClB,YAAY,0BAA0B,SAAS;AAAA,YAC/C,YAAY,SAAS;AAAA,YACrB,sBAAsB;AAAA,UACxB,CAAC;AAAA,QACH;AAAA,QACA,MAAM,eAAe,IAAI,QAAQ,OAAO,WAAW,OAAO,qBAAqB;AAAA,QAC/E,MAAM,kBAAkB,IAAI,QAAQ,OAAO,UAAU;AAAA,MACvD;AAAA,IACF,CAAC;AAQD,UAAM,YAAY,OAAO;AAEzB,UAAM,mBAAmB,cAAc,QAAQ,QAAQ,cAAc,UAAU,SAAS;AACxF,QAAI,mBAAmB,cAAc,qBAAqB,SAAS,qBAAqB,SAAS;AAC/F,YAAM,eAAe,qBAAqB,QAAQ,uBAAuB;AACzE,UAAI;AACF,cAAM,WAAW,IAAI,UAAU,QAAQ,UAAU;AACjD,YAAI,UAAU;AACZ,gBAAM,SAAS;AAAA,YACb;AAAA,YACA;AAAA,cACE,IAAI,OAAO;AAAA,cACX,UAAU,OAAO;AAAA,cACjB,gBAAgB,OAAO;AAAA,cACvB,aAAa,OAAO,eAAe;AAAA,cACnC,OAAO,OAAO;AAAA,cACd,aAAa,OAAO,eAAe;AAAA,cACnC,eAAe,OAAO,iBAAiB;AAAA,YACzC;AAAA,YACA;AAAA,cACE,YAAY;AAAA,cACZ,UAAU,OAAO;AAAA,cACjB,gBAAgB,OAAO;AAAA,YACzB;AAAA,UACF;AAAA,QACF;AAAA,MACF,SAAS,KAAK;AACZ,eAAO,KAAK,kCAAkC,EAAE,WAAW,gBAAgB,cAAc,IAAI,CAAC;AAAA,MAChG;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,OAAO,GAAG;AAAA,EAC7B;AAAA,EACA,cAAc,OAAO,QAAQ,QAAQ,QAAQ;AAC3C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,WAAO,MAAM,iBAAiB,IAAI,OAAO,MAAM;AAAA,EACjD;AAAA,EACA,UAAU,OAAO,EAAE,QAAQ,WAAW,IAAI,MAAM;AAC9C,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,gBAAgB,MAAM,iBAAiB,IAAI,OAAO,MAAM;AAC9D,WAAO;AAAA,MACL,aAAa,UAAU,gCAAgC,aAAa;AAAA,MACpE,cAAc;AAAA,MACd,YAAY,OAAO,KAAK;AAAA,MACxB,UAAU,OAAO,KAAK;AAAA,MACtB,gBAAgB,OAAO,KAAK;AAAA,MAC5B,gBAAgB;AAAA,MAChB,eAAe,iBAAiB;AAAA,MAChC,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,UACA,OAAO,iBAAiB;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAoC,QAAQ;AAC5D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,mCAAmC,sBAAsB,MAAM,IAAI,IAAI;AAC7E,QAAI,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,OAAO,KAAK,GAAG,CAAC;AAC/E,QAAI,CAAC,MAAM;AACT,aAAO,GAAG,OAAO,cAAc;AAAA,QAC7B,IAAI,OAAO,KAAK;AAAA,QAChB,gBAAgB,OAAO,KAAK;AAAA,QAC5B,UAAU,OAAO,KAAK;AAAA,QACtB,OAAO,OAAO,KAAK;AAAA,QACnB,aAAa,OAAO,KAAK;AAAA,QACzB,QAAQ,OAAO,KAAK;AAAA,QACpB,eAAe,OAAO,KAAK;AAAA,QAC3B,YAAY,OAAO,KAAK;AAAA,QACxB,iBAAiB,OAAO,KAAK;AAAA,QAC7B,aAAa,OAAO,KAAK;AAAA,QACzB,eAAe,OAAO,KAAK;AAAA,QAC3B,aAAa,OAAO,KAAK;AAAA,QACzB,iBAAiB,mBAAmB,OAAO,KAAK,iBAAiB,iBAAiB;AAAA,QAClF,aAAa,OAAO,KAAK;AAAA,QACzB,QAAQ,OAAO,KAAK;AAAA,QACpB,gBAAgB,OAAO,KAAK;AAAA,QAC5B,cAAc,OAAO,KAAK;AAAA,QAC1B,WAAW,OAAO,KAAK;AAAA,MACzB,CAAC;AACD,SAAG,QAAQ,IAAI;AAAA,IACjB;AACA,UAAM,wBAAwB,OAAO,KAAK,kBACtC,MAAM,0BAA0B,IAAI,OAAO,KAAK,iBAAiB,OAAO,KAAK,UAAU,OAAO,KAAK,cAAc,IACjH;AACJ,UAAM,qBAAqB,OAAO,KAAK,kBACnC,OAAO,YAAY,KAAK,CAAC,eAAe,WAAW,YAAY,OAAO,KAAK,eAAe,KAAK,OAC/F;AACJ,UAAM,+BACJ,OAAO,KAAK,qBAAqB,SAAS,OAAO,KAAK,mBAAmB,SACzE,CAAC,CAAC,OAAO,KAAK,mBACd,CAAC,EAAE,uBAAuB,cAAc,OAAO,KAAK,cAAc,oBAAoB,eACtF,CAAC,EAAE,uBAAuB,SAAS,OAAO,KAAK,iBAAiB,oBAAoB;AAEtF,UAAM,gBAAgB,IAAI;AAAA,MACxB,MAAM;AACJ,aAAK,QAAQ,OAAO,KAAK;AACzB,aAAK,cAAc,OAAO,KAAK;AAC/B,aAAK,SAAS,OAAO,KAAK;AAC1B,aAAK,gBAAgB,OAAO,KAAK;AACjC,aAAK,aAAa,OAAO,KAAK;AAC9B,aAAK,kBAAkB,OAAO,KAAK;AACnC,aAAK,cAAc,OAAO,KAAK;AAC/B,aAAK,gBAAgB,OAAO,KAAK;AACjC,aAAK,cAAc,OAAO,KAAK;AAC/B,aAAK,kBAAkB,mBAAmB,OAAO,KAAK,iBAAiB,iBAAiB;AACxF,aAAK,cAAc,OAAO,KAAK;AAC/B,aAAK,SAAS,OAAO,KAAK;AAC1B,aAAK,iBAAiB,OAAO,KAAK;AAClC,aAAK,eAAe,OAAO,KAAK;AAChC,aAAK,YAAY,OAAO,KAAK;AAAA,MAC/B;AAAA,MACA,YAAY;AAMV,cAAM,GAAG,MAAM;AAAA,MACjB;AAAA,MACA,YAAY;AACV,YAAI,CAAC,gCAAgC,CAAC,OAAO,KAAK,gBAAiB;AACnE,cAAM,aAAa,uBAAuB,cAAc,OAAO,KAAK,cAAc,oBAAoB;AACtG,cAAM,aAAa,uBAAuB,SAAS,OAAO,KAAK,iBAAiB,oBAAoB;AACpG,YAAI,CAAC,cAAc,CAAC,WAAY;AAChC,cAAM,0BAA0B,IAAI;AAAA,UAClC;AAAA,UACA;AAAA,UACA,SAAS,OAAO,KAAK;AAAA,UACrB;AAAA,UACA,YAAY,uBAAuB,SAAS,oBAAoB,cAAc;AAAA,UAC9E,sBAAsB;AAAA,QACxB,CAAC;AAAA,MACH;AAAA,MACA,MAAM,eAAe,IAAI,MAAM,OAAO,QAAQ,OAAO,qBAAqB;AAAA,MAC1E,MAAM,kBAAkB,IAAI,MAAM,OAAO,SAAS;AAAA,IACpD,GAAG,EAAE,aAAa,KAAK,CAAC;AAExB,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,wBAAwB;AAAA,MAC5B,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,KAAK;AAAA,QACT,gBAAgB,KAAK;AAAA,QACrB,UAAU,KAAK;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,cAAc,yBAAyB,OAAO,QAAQ,SAAS,OAAO,MAAM;AAClF,QAAI,OAAO,KAAK,WAAW,EAAE,QAAQ;AACnC,YAAM,qBAAqB;AAAA,QACzB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,MAAM,oBACJ;AAAA,EACE,IAAI;AAAA,EACJ,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,kBAAkB;AAC9C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,WAAW,MAAM,iBAAiB,IAAI,EAAE;AAC9C,WAAO,WAAW,EAAE,QAAQ,SAAS,IAAI,CAAC;AAAA,EAC5C;AAAA,EACA,MAAM,QAAQ,OAAO,KAAK;AACxB,UAAM,KAAK,UAAU,OAAO,kBAAkB;AAC9C,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,UAAM,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,WAAW,KAAK,CAAC;AAClF,UAAM,SAAS,QAAQ;AACvB,QAAI,CAAC,OAAQ,OAAM,SAAS,gBAAgB;AAC5C,sBAAkB,KAAK,OAAO,QAAQ;AACtC,4BAAwB,KAAK,OAAO,cAAc;AAClD,UAAM,2BAA2B,IAAI,MAAM;AAC3C,UAAM,GAAG,aAAa,wBAAwB,EAAE,MAAM,OAAO,CAAC;AAC9D,UAAM,GAAG,aAAa,yBAAyB,EAAE,MAAM,OAAO,CAAC;AAC/D,OAAG,OAAO,MAAM;AAChB,UAAM,GAAG,MAAM;AAEf,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,oBAAoB;AAAA,MACxB,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,OAAO;AAAA,QACX,gBAAgB,OAAO;AAAA,QACvB,UAAU,OAAO;AAAA,MACnB;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AACD,WAAO,EAAE,QAAQ,OAAO,GAAG;AAAA,EAC7B;AAAA,EACA,UAAU,OAAO,EAAE,UAAU,MAAM;AACjC,UAAM,SAAS,UAAU;AACzB,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO;AAAA,MACL,aAAa,UAAU,gCAAgC,aAAa;AAAA,MACpE,cAAc;AAAA,MACd,YAAY,OAAO,KAAK;AAAA,MACxB,UAAU,OAAO,KAAK;AAAA,MACtB,gBAAgB,OAAO,KAAK;AAAA,MAC5B,gBAAgB;AAAA,MAChB,SAAS;AAAA,QACP,MAAM;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,OAAO,EAAE,UAAU,IAAI,MAAM;AACjC,UAAM,UAAU,mBAAoC,QAAQ;AAC5D,UAAM,SAAS,SAAS;AACxB,QAAI,CAAC,OAAQ;AACb,UAAM,KAAM,IAAI,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAC/D,QAAI,OAAO,MAAM,sBAAsB,IAAI,cAAc,EAAE,IAAI,OAAO,KAAK,GAAG,CAAC;AAC/E,QAAI,CAAC,MAAM;AACT,aAAO,GAAG,OAAO,cAAc;AAAA,QAC7B,IAAI,OAAO,KAAK;AAAA,QAChB,gBAAgB,OAAO,KAAK;AAAA,QAC5B,UAAU,OAAO,KAAK;AAAA,QACtB,OAAO,OAAO,KAAK;AAAA,QACnB,aAAa,OAAO,KAAK;AAAA,QACzB,QAAQ,OAAO,KAAK;AAAA,QACpB,eAAe,OAAO,KAAK;AAAA,QAC3B,YAAY,OAAO,KAAK;AAAA,QACxB,iBAAiB,OAAO,KAAK;AAAA,QAC7B,aAAa,OAAO,KAAK;AAAA,QACzB,eAAe,OAAO,KAAK;AAAA,QAC3B,aAAa,OAAO,KAAK;AAAA,QACzB,iBAAiB,mBAAmB,OAAO,KAAK,iBAAiB,iBAAiB;AAAA,QAClF,aAAa,OAAO,KAAK;AAAA,QACzB,QAAQ,OAAO,KAAK;AAAA,QACpB,gBAAgB,OAAO,KAAK;AAAA,QAC5B,cAAc,OAAO,KAAK;AAAA,QAC1B,WAAW,OAAO,KAAK;AAAA,MACzB,CAAC;AACD,SAAG,QAAQ,IAAI;AAAA,IACjB;AACA,UAAM,gBAAgB,IAAI;AAAA,MACxB,MAAM,eAAe,IAAI,MAAM,OAAO,QAAQ,OAAO,qBAAqB;AAAA,MAC1E,MAAM,kBAAkB,IAAI,MAAM,OAAO,SAAS;AAAA,MAClD,MAAM,2BAA2B,IAAI,IAAI;AAAA,MACzC,MAAM,4BAA4B,IAAI,MAAM,OAAO,WAAW;AAAA,IAChE,GAAG,EAAE,aAAa,KAAK,CAAC;AAExB,UAAM,KAAM,IAAI,UAAU,QAAQ,YAAY;AAC9C,UAAM,wBAAwB;AAAA,MAC5B,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,aAAa;AAAA,QACX,IAAI,KAAK;AAAA,QACT,gBAAgB,KAAK;AAAA,QACrB,UAAU,KAAK;AAAA,MACjB;AAAA,MACA,SAAS;AAAA,MACT,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,cAAc,yBAAyB,OAAO,QAAQ,MAAS;AACrE,QAAI,OAAO,KAAK,WAAW,EAAE,QAAQ;AACnC,YAAM,qBAAqB;AAAA,QACzB,YAAY;AAAA,QACZ,UAAU;AAAA,QACV,UAAU,KAAK;AAAA,QACf,gBAAgB,KAAK;AAAA,QACrB,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEF,gBAAgB,iBAAiB;AACjC,gBAAgB,iBAAiB;AACjC,gBAAgB,iBAAiB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/customers/components/detail/pipelineStageUtils.ts"],
|
|
4
|
-
"sourcesContent": ["export function normalizePipelineStageLabel(value: string | null | undefined): string {\n return typeof value === 'string'\n ? value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim()\n : ''\n}\n\nconst TERMINAL_OUTCOME_LABELS = new Set([\n 'won',\n 'win',\n 'closed won',\n 'closed win',\n 'lost',\n 'loose',\n 'closed lost',\n 'closed loose',\n 'stalled',\n 'stale',\n 'closed stalled',\n 'closed stale',\n])\n\nexport function isTerminalPipelineOutcomeLabel(value: string | null | undefined): boolean {\n const normalized = normalizePipelineStageLabel(value)\n return normalized.length > 0 && TERMINAL_OUTCOME_LABELS.has(normalized)\n}\n"],
|
|
5
|
-
"mappings": "AAAO,SAAS,4BAA4B,OAA0C;AACpF,SAAO,OAAO,UAAU,WACpB,MACG,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,KAAK,IACR;AACN;AAEA,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"sourcesContent": ["export function normalizePipelineStageLabel(value: string | null | undefined): string {\n return typeof value === 'string'\n ? value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim()\n : ''\n}\n\nconst TERMINAL_OUTCOME_LABELS = new Set([\n 'won',\n 'win',\n 'closed won',\n 'closed win',\n 'lost',\n // Pre-0.7.1 misspelling; unmigrated stage labels still carry it.\n 'loose',\n 'closed lost',\n 'closed loose',\n 'stalled',\n 'stale',\n 'closed stalled',\n 'closed stale',\n])\n\nexport function isTerminalPipelineOutcomeLabel(value: string | null | undefined): boolean {\n const normalized = normalizePipelineStageLabel(value)\n return normalized.length > 0 && TERMINAL_OUTCOME_LABELS.has(normalized)\n}\n"],
|
|
5
|
+
"mappings": "AAAO,SAAS,4BAA4B,OAA0C;AACpF,SAAO,OAAO,UAAU,WACpB,MACG,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,KAAK,IACR;AACN;AAEA,MAAM,0BAA0B,oBAAI,IAAI;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEM,SAAS,+BAA+B,OAA2C;AACxF,QAAM,aAAa,4BAA4B,KAAK;AACpD,SAAO,WAAW,SAAS,KAAK,wBAAwB,IAAI,UAAU;AACxE;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -159,7 +159,7 @@ function createDealLinkAdapter(options) {
|
|
|
159
159
|
{ id: "all", label: "All" },
|
|
160
160
|
{ id: "open", label: "Open" },
|
|
161
161
|
{ id: "win", label: "Won" },
|
|
162
|
-
{ id: "
|
|
162
|
+
{ id: "lost", label: "Lost" },
|
|
163
163
|
{
|
|
164
164
|
id: "orphan",
|
|
165
165
|
label: "Orphan",
|
|
@@ -172,7 +172,7 @@ function createDealLinkAdapter(options) {
|
|
|
172
172
|
if (!filterId || filterId === "all") return true;
|
|
173
173
|
const meta = option.meta ?? {};
|
|
174
174
|
if (filterId === "orphan") return meta.isOrphan === true;
|
|
175
|
-
if (filterId === "open" || filterId === "win" || filterId === "
|
|
175
|
+
if (filterId === "open" || filterId === "win" || filterId === "lost") {
|
|
176
176
|
return (meta.stage ?? "").toLowerCase().includes(filterId) || true;
|
|
177
177
|
}
|
|
178
178
|
return true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/components/linking/adapters/dealAdapter.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { AlertTriangle, Briefcase, CalendarDays, Link2 } from 'lucide-react'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type {\n LinkEntityAdapter,\n LinkEntityOption,\n LinkEntityRowContext,\n LinkEntitySearchPage,\n} from '../LinkEntityDialog'\n\ntype DealDetails = {\n id: string\n title: string\n code?: string | null\n createdAt?: string | null\n stage?: string | null\n pipeline?: { stages: Array<{ id: string; label: string }>; currentStageId?: string | null }\n value?: { amount: string; currency: string | null } | null\n nextStep?: { title: string; dueAt?: string | null; assignee?: string | null } | null\n keyPeople?: Array<{ id: string; name: string; role?: string | null }>\n anchors?: { companies: number; people: number }\n orphanWarningMessage?: string | null\n}\n\ntype DealAdapterOptions = {\n dialogTitle: string\n dialogSubtitle?: string\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n orphanWarningTitle: string\n orphanWarningMessage: string\n excludeIds?: string[]\n defaultAvatarIcon?: React.ReactNode\n pageSize?: number\n addNew?: LinkEntityAdapter<DealDetails>['addNew']\n contextEntityId?: string\n headerIcon?: React.ReactNode\n}\n\nconst DEFAULT_PAGE_SIZE = 20\n\ntype DealAssociationRecord = {\n id: string\n label: string\n subtitle: string | null\n}\n\nfunction parseStatusFilter(filterId?: string): string | null {\n if (!filterId || filterId === 'all' || filterId === 'orphan') return null\n return filterId\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null\n}\n\nfunction readTrimmedString(record: Record<string, unknown> | null, ...keys: string[]): string | null {\n if (!record) return null\n for (const key of keys) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction readDecimalValue(record: Record<string, unknown> | null, ...keys: string[]): string | null {\n if (!record) return null\n for (const key of keys) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length) {\n return value.trim()\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return String(value)\n }\n }\n return null\n}\n\nfunction normalizeAssociationRecord(entry: unknown): DealAssociationRecord | null {\n const record = asRecord(entry)\n const id = readTrimmedString(record, 'id')\n if (!id) return null\n return {\n id,\n label:\n readTrimmedString(record, 'label', 'displayName', 'display_name', 'name', 'title') ?? id,\n subtitle: readTrimmedString(record, 'subtitle', 'role', 'roleLabel'),\n }\n}\n\nfunction normalizeDealRecord(record: Record<string, unknown>): LinkEntityOption | null {\n const id = typeof record.id === 'string' ? record.id : null\n if (!id) return null\n const title =\n typeof record.title === 'string' && record.title.trim().length\n ? record.title.trim()\n : typeof record.name === 'string' && record.name.trim().length\n ? record.name.trim()\n : null\n const label = title ?? id\n const code =\n typeof record.code === 'string'\n ? record.code\n : typeof record.reference === 'string'\n ? record.reference\n : null\n const valueAmount =\n typeof record.valueAmount === 'string'\n ? record.valueAmount\n : typeof record.value_amount === 'string'\n ? record.value_amount\n : typeof record.value === 'number'\n ? String(record.value)\n : null\n const valueCurrency =\n typeof record.valueCurrency === 'string'\n ? record.valueCurrency\n : typeof record.value_currency === 'string'\n ? record.value_currency\n : null\n const stage =\n typeof record.pipelineStage === 'string'\n ? record.pipelineStage\n : typeof record.pipeline_stage === 'string'\n ? record.pipeline_stage\n : typeof record.status === 'string'\n ? record.status\n : null\n const updatedAt =\n typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : typeof record.createdAt === 'string'\n ? record.createdAt\n : typeof record.created_at === 'string'\n ? record.created_at\n : null\n const anchorCompanies =\n typeof (record.companies as { length?: number })?.length === 'number'\n ? (record.companies as unknown[]).length\n : typeof record.companyCount === 'number'\n ? record.companyCount\n : null\n const isOrphan = anchorCompanies !== null ? anchorCompanies === 0 : undefined\n const companyName =\n typeof record.companyName === 'string'\n ? record.companyName\n : Array.isArray(record.companies) && record.companies.length > 0\n ? normalizeAssociationRecord(record.companies[0])?.label ?? null\n : null\n return {\n id,\n label,\n subtitle: null,\n meta: {\n code,\n valueAmount,\n valueCurrency,\n stage,\n updatedAt,\n isOrphan,\n companyName: typeof companyName === 'string' ? companyName : null,\n },\n }\n}\n\nasync function fetchDealDetails(id: string, contextEntityId?: string): Promise<DealDetails> {\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals/${encodeURIComponent(id)}`,\n )\n const rootRecord = asRecord(payload)\n const dealRecord = asRecord(rootRecord?.deal) ?? rootRecord\n const title =\n readTrimmedString(dealRecord, 'title', 'name') ?? id\n const code = readTrimmedString(dealRecord, 'code', 'reference')\n const createdAt = readTrimmedString(dealRecord, 'createdAt', 'created_at')\n const valueAmount = readDecimalValue(dealRecord, 'valueAmount', 'value_amount', 'value')\n const valueCurrency = readTrimmedString(\n dealRecord,\n 'valueCurrency',\n 'value_currency',\n 'currency',\n )\n const stage = readTrimmedString(dealRecord, 'pipelineStage', 'pipeline_stage', 'status')\n const companies = Array.isArray(rootRecord?.companies)\n ? rootRecord.companies\n .map((entry) => normalizeAssociationRecord(entry))\n .filter((entry): entry is DealAssociationRecord => entry !== null)\n : []\n const people = Array.isArray(rootRecord?.people)\n ? rootRecord.people\n .map((entry) => normalizeAssociationRecord(entry))\n .filter((entry): entry is DealAssociationRecord => entry !== null)\n : []\n const companiesCount = companies.filter((entry) => {\n return !contextEntityId || entry.id !== contextEntityId\n }).length\n const peopleCount = people.filter((entry) => {\n return !contextEntityId || entry.id !== contextEntityId\n }).length\n const keyPeople = people.slice(0, 3).map((entry) => ({\n id: entry.id,\n name: entry.label,\n role: entry.subtitle,\n }))\n return {\n id,\n title,\n code,\n createdAt,\n stage,\n value: valueAmount ? { amount: valueAmount, currency: valueCurrency ?? null } : null,\n nextStep: null,\n keyPeople,\n anchors: { companies: companiesCount, people: peopleCount },\n }\n } catch {\n return {\n id,\n title: id,\n code: null,\n createdAt: null,\n stage: null,\n value: null,\n nextStep: null,\n keyPeople: [],\n anchors: { companies: 0, people: 0 },\n }\n }\n}\n\nfunction formatValue(amount: string | null, currency: string | null): string | null {\n if (!amount) return null\n const parsed = parseFloat(amount)\n if (!Number.isFinite(parsed)) return amount\n const formatted = parsed.toLocaleString(undefined, { maximumFractionDigits: 2 })\n return currency ? `${formatted} ${currency}` : formatted\n}\n\nfunction formatRelative(dateString: string | null): string {\n if (!dateString) return ''\n try {\n const date = new Date(dateString)\n const now = Date.now()\n const diffMs = now - date.getTime()\n const diffDays = Math.floor(diffMs / 86_400_000)\n if (diffDays <= 0) return 'today'\n if (diffDays === 1) return 'yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`\n return `${Math.floor(diffDays / 365)} years ago`\n } catch {\n return ''\n }\n}\n\nexport function createDealLinkAdapter(options: DealAdapterOptions): LinkEntityAdapter<DealDetails> {\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE\n\n const filters = {\n options: [\n { id: 'all', label: 'All' },\n { id: 'open', label: 'Open' },\n { id: 'win', label: 'Won' },\n { id: 'loose', label: 'Lost' },\n { id: 'orphan', label: 'Orphan', dotColor: '#eb9426' /* TODO(ds-review): #eb9426 \u2014 requires LinkEntityDialog to support semantic token classNames */ },\n ],\n defaultId: 'all',\n clientFilter: (option: LinkEntityOption, filterId: string) => {\n if (!filterId || filterId === 'all') return true\n const meta = (option.meta ?? {}) as { isOrphan?: boolean; stage?: string | null }\n if (filterId === 'orphan') return meta.isOrphan === true\n // Server-side status filter already applied; this keeps all rows if server honored the filter.\n // Fallback client check on stage in case server returns mixed statuses.\n if (filterId === 'open' || filterId === 'win' || filterId === 'loose') {\n return (meta.stage ?? '').toLowerCase().includes(filterId) || true\n }\n return true\n },\n }\n\n const searchPage = async (\n query: string,\n page: number,\n filterId?: string,\n ): Promise<LinkEntitySearchPage> => {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const status = parseStatusFilter(filterId)\n if (status) {\n params.set('status', status)\n }\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const exclude = new Set(options.excludeIds ?? [])\n let items = rawItems\n .map((candidate) =>\n candidate && typeof candidate === 'object'\n ? normalizeDealRecord(candidate as Record<string, unknown>)\n : null,\n )\n .filter((entry): entry is LinkEntityOption => entry !== null && !exclude.has(entry.id))\n if (filterId === 'orphan') {\n items = items.filter((item) => (item.meta as { isOrphan?: boolean }).isOrphan === true)\n }\n const totalPages = typeof payload.totalPages === 'number' ? payload.totalPages : 1\n const total = typeof payload.total === 'number' ? payload.total : undefined\n return { items, totalPages, total }\n }\n\n const fetchByIds = async (ids: string[]): Promise<LinkEntityOption[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n try {\n const payload = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/customers/deals?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, LinkEntityOption>()\n rawItems.forEach((record) => {\n if (!record || typeof record !== 'object') return\n const option = normalizeDealRecord(record as Record<string, unknown>)\n if (option) byId.set(option.id, option)\n })\n return uniqueIds.map((id) => byId.get(id) ?? { id, label: id, subtitle: null })\n } catch {\n return uniqueIds.map((id) => ({ id, label: id, subtitle: null }))\n }\n }\n\n const renderRow = (option: LinkEntityOption, ctx: LinkEntityRowContext): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n code?: string | null\n valueAmount?: string | null\n valueCurrency?: string | null\n stage?: string | null\n updatedAt?: string | null\n isOrphan?: boolean\n companyName?: string | null\n }\n const formattedValue = formatValue(meta.valueAmount ?? null, meta.valueCurrency ?? null)\n return (\n <>\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-md bg-muted/80 text-muted-foreground\">\n <Briefcase className=\"size-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-1.5\">\n <span className=\"truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {meta.code ? (\n <span className=\"inline-flex items-center rounded-sm bg-muted px-1.5 py-0.5 text-xs font-semibold uppercase text-muted-foreground\">\n {meta.code}\n </span>\n ) : null}\n {meta.isOrphan ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg px-2 py-0.5 text-xs font-semibold text-status-warning-text\">\n <span aria-hidden=\"true\" className=\"inline-block size-1.5 rounded-full bg-status-warning-icon\" />\n no company\n </span>\n ) : null}\n </div>\n <div className=\"mt-0.5 flex min-w-0 flex-wrap items-center gap-2 text-xs text-muted-foreground\">\n {formattedValue ? (\n <span className=\"font-semibold text-foreground\">{formattedValue}</span>\n ) : null}\n {meta.stage ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span>{meta.stage}</span>\n </>\n ) : null}\n {meta.companyName ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span className=\"truncate\">{meta.companyName}</span>\n </>\n ) : null}\n {meta.updatedAt ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span>{formatRelative(meta.updatedAt)}</span>\n </>\n ) : null}\n </div>\n </div>\n <span\n role=\"checkbox\"\n aria-checked={ctx.selected}\n aria-label={`Select ${option.label}`}\n className={cn(\n 'inline-flex size-5 shrink-0 items-center justify-center rounded-full border',\n ctx.selected\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n )}\n >\n {ctx.selected ? (\n <svg viewBox=\"0 0 12 12\" className=\"size-3\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.5 6.5l2.5 2.5 4.5-5\" />\n </svg>\n ) : null}\n </span>\n </>\n )\n }\n\n const renderPreview = (\n option: LinkEntityOption,\n details?: DealDetails,\n ): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n code?: string | null\n valueAmount?: string | null\n valueCurrency?: string | null\n isOrphan?: boolean\n }\n const derived = details ?? {\n id: option.id,\n title: option.label,\n code: meta.code ?? null,\n createdAt: null,\n stage: null,\n value: meta.valueAmount ? { amount: meta.valueAmount, currency: meta.valueCurrency ?? null } : null,\n nextStep: null,\n keyPeople: [],\n anchors: undefined,\n }\n const isOrphan = meta.isOrphan || (derived.anchors ? derived.anchors.companies === 0 : false)\n const formattedValue = derived.value ? formatValue(derived.value.amount, derived.value.currency) : null\n const createdRel = derived.createdAt ? `Created ${formatRelative(derived.createdAt)}` : null\n return (\n <div className=\"flex flex-col gap-3.5 rounded-xl border border-border/70 bg-card p-4\">\n <div>\n <div className=\"text-base font-bold text-foreground\">{derived.title}</div>\n <div className=\"mt-1 flex items-center gap-1.5 text-xs text-muted-foreground\">\n {derived.code ? <span>{derived.code}</span> : null}\n {derived.code && createdRel ? <span>\u00B7</span> : null}\n {createdRel ? <span>{createdRel}</span> : null}\n </div>\n </div>\n\n {isOrphan ? (\n <div className=\"flex items-start gap-2 rounded-md bg-status-warning-bg px-3 py-2.5\">\n <AlertTriangle className=\"mt-0.5 size-3.5 text-status-warning-icon\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs font-semibold text-status-warning-text\">\n {options.orphanWarningTitle}\n </div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {options.orphanWarningMessage}\n </div>\n </div>\n </div>\n ) : null}\n\n {formattedValue ? (\n <div className=\"flex items-baseline gap-3\">\n <div className=\"text-2xl font-bold text-foreground\">{formattedValue}</div>\n <div className=\"text-xs text-muted-foreground\">potential value</div>\n </div>\n ) : null}\n\n {derived.stage ? (\n <>\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Stage\n </div>\n <div className=\"flex items-center gap-1.5\">\n <span className=\"inline-block size-2 rounded-full bg-foreground\" />\n <span className=\"text-xs font-semibold text-foreground\">{derived.stage}</span>\n </div>\n </>\n ) : null}\n\n {derived.nextStep ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Next step\n </div>\n <div className=\"flex items-start gap-2\">\n <CalendarDays className=\"mt-0.5 size-3 text-muted-foreground\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-xs font-semibold text-foreground\">\n {derived.nextStep.title}\n </div>\n {derived.nextStep.assignee ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n Assigned: {derived.nextStep.assignee}\n </div>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n\n {derived.keyPeople && derived.keyPeople.length > 0 ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Key people ({derived.keyPeople.length})\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {derived.keyPeople.map((person) => (\n <div\n key={person.id || person.name}\n className=\"flex items-center gap-2 rounded-md bg-muted/60 px-2.5 py-1.5\"\n >\n <Avatar label={person.name} variant=\"monochrome\" size=\"sm\" />\n <span className=\"text-xs font-semibold text-foreground\">{person.name}</span>\n {person.role ? (\n <span className=\"ml-auto inline-flex items-center rounded-sm border border-border px-1.5 py-0.5 text-xs font-semibold text-muted-foreground\">\n {person.role}\n </span>\n ) : null}\n </div>\n ))}\n </div>\n </>\n ) : null}\n </div>\n )\n }\n\n const computeOrphanWarning = async (option: LinkEntityOption): Promise<string | null> => {\n const details = await fetchDealDetails(option.id, options.contextEntityId)\n const anchors = details.anchors ?? { companies: 0, people: 0 }\n return anchors.companies + anchors.people < 1 ? options.orphanWarningMessage : null\n }\n\n return {\n kind: 'deal',\n dialogTitle: options.dialogTitle,\n dialogSubtitle: options.dialogSubtitle,\n sectionLabel: options.sectionLabel ?? 'MATCHING DEALS',\n searchPlaceholder: options.searchPlaceholder,\n searchEmptyHint: options.searchEmptyHint,\n selectedEmptyHint: options.selectedEmptyHint,\n confirmButtonLabel: options.confirmButtonLabel,\n defaultAvatarIcon: options.defaultAvatarIcon,\n headerIcon: options.headerIcon ?? <Link2 className=\"size-5\" />,\n filters,\n renderRow,\n renderPreview,\n fetchDetails: (id) => fetchDealDetails(id, options.contextEntityId),\n searchPage,\n fetchByIds,\n computeOrphanWarning,\n addNew: options.addNew,\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { AlertTriangle, Briefcase, CalendarDays, Link2 } from 'lucide-react'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Avatar } from '@open-mercato/ui/primitives/avatar'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport type {\n LinkEntityAdapter,\n LinkEntityOption,\n LinkEntityRowContext,\n LinkEntitySearchPage,\n} from '../LinkEntityDialog'\n\ntype DealDetails = {\n id: string\n title: string\n code?: string | null\n createdAt?: string | null\n stage?: string | null\n pipeline?: { stages: Array<{ id: string; label: string }>; currentStageId?: string | null }\n value?: { amount: string; currency: string | null } | null\n nextStep?: { title: string; dueAt?: string | null; assignee?: string | null } | null\n keyPeople?: Array<{ id: string; name: string; role?: string | null }>\n anchors?: { companies: number; people: number }\n orphanWarningMessage?: string | null\n}\n\ntype DealAdapterOptions = {\n dialogTitle: string\n dialogSubtitle?: string\n sectionLabel?: string\n searchPlaceholder: string\n searchEmptyHint: string\n selectedEmptyHint: string\n confirmButtonLabel: string\n orphanWarningTitle: string\n orphanWarningMessage: string\n excludeIds?: string[]\n defaultAvatarIcon?: React.ReactNode\n pageSize?: number\n addNew?: LinkEntityAdapter<DealDetails>['addNew']\n contextEntityId?: string\n headerIcon?: React.ReactNode\n}\n\nconst DEFAULT_PAGE_SIZE = 20\n\ntype DealAssociationRecord = {\n id: string\n label: string\n subtitle: string | null\n}\n\nfunction parseStatusFilter(filterId?: string): string | null {\n if (!filterId || filterId === 'all' || filterId === 'orphan') return null\n return filterId\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null\n}\n\nfunction readTrimmedString(record: Record<string, unknown> | null, ...keys: string[]): string | null {\n if (!record) return null\n for (const key of keys) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length) {\n return value.trim()\n }\n }\n return null\n}\n\nfunction readDecimalValue(record: Record<string, unknown> | null, ...keys: string[]): string | null {\n if (!record) return null\n for (const key of keys) {\n const value = record[key]\n if (typeof value === 'string' && value.trim().length) {\n return value.trim()\n }\n if (typeof value === 'number' && Number.isFinite(value)) {\n return String(value)\n }\n }\n return null\n}\n\nfunction normalizeAssociationRecord(entry: unknown): DealAssociationRecord | null {\n const record = asRecord(entry)\n const id = readTrimmedString(record, 'id')\n if (!id) return null\n return {\n id,\n label:\n readTrimmedString(record, 'label', 'displayName', 'display_name', 'name', 'title') ?? id,\n subtitle: readTrimmedString(record, 'subtitle', 'role', 'roleLabel'),\n }\n}\n\nfunction normalizeDealRecord(record: Record<string, unknown>): LinkEntityOption | null {\n const id = typeof record.id === 'string' ? record.id : null\n if (!id) return null\n const title =\n typeof record.title === 'string' && record.title.trim().length\n ? record.title.trim()\n : typeof record.name === 'string' && record.name.trim().length\n ? record.name.trim()\n : null\n const label = title ?? id\n const code =\n typeof record.code === 'string'\n ? record.code\n : typeof record.reference === 'string'\n ? record.reference\n : null\n const valueAmount =\n typeof record.valueAmount === 'string'\n ? record.valueAmount\n : typeof record.value_amount === 'string'\n ? record.value_amount\n : typeof record.value === 'number'\n ? String(record.value)\n : null\n const valueCurrency =\n typeof record.valueCurrency === 'string'\n ? record.valueCurrency\n : typeof record.value_currency === 'string'\n ? record.value_currency\n : null\n const stage =\n typeof record.pipelineStage === 'string'\n ? record.pipelineStage\n : typeof record.pipeline_stage === 'string'\n ? record.pipeline_stage\n : typeof record.status === 'string'\n ? record.status\n : null\n const updatedAt =\n typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : typeof record.createdAt === 'string'\n ? record.createdAt\n : typeof record.created_at === 'string'\n ? record.created_at\n : null\n const anchorCompanies =\n typeof (record.companies as { length?: number })?.length === 'number'\n ? (record.companies as unknown[]).length\n : typeof record.companyCount === 'number'\n ? record.companyCount\n : null\n const isOrphan = anchorCompanies !== null ? anchorCompanies === 0 : undefined\n const companyName =\n typeof record.companyName === 'string'\n ? record.companyName\n : Array.isArray(record.companies) && record.companies.length > 0\n ? normalizeAssociationRecord(record.companies[0])?.label ?? null\n : null\n return {\n id,\n label,\n subtitle: null,\n meta: {\n code,\n valueAmount,\n valueCurrency,\n stage,\n updatedAt,\n isOrphan,\n companyName: typeof companyName === 'string' ? companyName : null,\n },\n }\n}\n\nasync function fetchDealDetails(id: string, contextEntityId?: string): Promise<DealDetails> {\n try {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals/${encodeURIComponent(id)}`,\n )\n const rootRecord = asRecord(payload)\n const dealRecord = asRecord(rootRecord?.deal) ?? rootRecord\n const title =\n readTrimmedString(dealRecord, 'title', 'name') ?? id\n const code = readTrimmedString(dealRecord, 'code', 'reference')\n const createdAt = readTrimmedString(dealRecord, 'createdAt', 'created_at')\n const valueAmount = readDecimalValue(dealRecord, 'valueAmount', 'value_amount', 'value')\n const valueCurrency = readTrimmedString(\n dealRecord,\n 'valueCurrency',\n 'value_currency',\n 'currency',\n )\n const stage = readTrimmedString(dealRecord, 'pipelineStage', 'pipeline_stage', 'status')\n const companies = Array.isArray(rootRecord?.companies)\n ? rootRecord.companies\n .map((entry) => normalizeAssociationRecord(entry))\n .filter((entry): entry is DealAssociationRecord => entry !== null)\n : []\n const people = Array.isArray(rootRecord?.people)\n ? rootRecord.people\n .map((entry) => normalizeAssociationRecord(entry))\n .filter((entry): entry is DealAssociationRecord => entry !== null)\n : []\n const companiesCount = companies.filter((entry) => {\n return !contextEntityId || entry.id !== contextEntityId\n }).length\n const peopleCount = people.filter((entry) => {\n return !contextEntityId || entry.id !== contextEntityId\n }).length\n const keyPeople = people.slice(0, 3).map((entry) => ({\n id: entry.id,\n name: entry.label,\n role: entry.subtitle,\n }))\n return {\n id,\n title,\n code,\n createdAt,\n stage,\n value: valueAmount ? { amount: valueAmount, currency: valueCurrency ?? null } : null,\n nextStep: null,\n keyPeople,\n anchors: { companies: companiesCount, people: peopleCount },\n }\n } catch {\n return {\n id,\n title: id,\n code: null,\n createdAt: null,\n stage: null,\n value: null,\n nextStep: null,\n keyPeople: [],\n anchors: { companies: 0, people: 0 },\n }\n }\n}\n\nfunction formatValue(amount: string | null, currency: string | null): string | null {\n if (!amount) return null\n const parsed = parseFloat(amount)\n if (!Number.isFinite(parsed)) return amount\n const formatted = parsed.toLocaleString(undefined, { maximumFractionDigits: 2 })\n return currency ? `${formatted} ${currency}` : formatted\n}\n\nfunction formatRelative(dateString: string | null): string {\n if (!dateString) return ''\n try {\n const date = new Date(dateString)\n const now = Date.now()\n const diffMs = now - date.getTime()\n const diffDays = Math.floor(diffMs / 86_400_000)\n if (diffDays <= 0) return 'today'\n if (diffDays === 1) return 'yesterday'\n if (diffDays < 30) return `${diffDays} days ago`\n if (diffDays < 365) return `${Math.floor(diffDays / 30)} months ago`\n return `${Math.floor(diffDays / 365)} years ago`\n } catch {\n return ''\n }\n}\n\nexport function createDealLinkAdapter(options: DealAdapterOptions): LinkEntityAdapter<DealDetails> {\n const pageSize = options.pageSize ?? DEFAULT_PAGE_SIZE\n\n const filters = {\n options: [\n { id: 'all', label: 'All' },\n { id: 'open', label: 'Open' },\n { id: 'win', label: 'Won' },\n { id: 'lost', label: 'Lost' },\n { id: 'orphan', label: 'Orphan', dotColor: '#eb9426' /* TODO(ds-review): #eb9426 \u2014 requires LinkEntityDialog to support semantic token classNames */ },\n ],\n defaultId: 'all',\n clientFilter: (option: LinkEntityOption, filterId: string) => {\n if (!filterId || filterId === 'all') return true\n const meta = (option.meta ?? {}) as { isOrphan?: boolean; stage?: string | null }\n if (filterId === 'orphan') return meta.isOrphan === true\n // Server-side status filter already applied; this keeps all rows if server honored the filter.\n // Fallback client check on stage in case server returns mixed statuses.\n if (filterId === 'open' || filterId === 'win' || filterId === 'lost') {\n return (meta.stage ?? '').toLowerCase().includes(filterId) || true\n }\n return true\n },\n }\n\n const searchPage = async (\n query: string,\n page: number,\n filterId?: string,\n ): Promise<LinkEntitySearchPage> => {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(pageSize),\n })\n if (query.trim().length > 0) {\n params.set('search', query.trim())\n }\n const status = parseStatusFilter(filterId)\n if (status) {\n params.set('status', status)\n }\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/customers/deals?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const exclude = new Set(options.excludeIds ?? [])\n let items = rawItems\n .map((candidate) =>\n candidate && typeof candidate === 'object'\n ? normalizeDealRecord(candidate as Record<string, unknown>)\n : null,\n )\n .filter((entry): entry is LinkEntityOption => entry !== null && !exclude.has(entry.id))\n if (filterId === 'orphan') {\n items = items.filter((item) => (item.meta as { isOrphan?: boolean }).isOrphan === true)\n }\n const totalPages = typeof payload.totalPages === 'number' ? payload.totalPages : 1\n const total = typeof payload.total === 'number' ? payload.total : undefined\n return { items, totalPages, total }\n }\n\n const fetchByIds = async (ids: string[]): Promise<LinkEntityOption[]> => {\n const uniqueIds = Array.from(new Set(ids.map((value) => value.trim()).filter(Boolean)))\n if (!uniqueIds.length) return []\n const params = new URLSearchParams({\n ids: uniqueIds.join(','),\n pageSize: String(Math.max(uniqueIds.length, 1)),\n })\n try {\n const payload = await readApiResultOrThrow<{ items?: Record<string, unknown>[] }>(\n `/api/customers/deals?${params.toString()}`,\n )\n const rawItems = Array.isArray(payload.items) ? payload.items : []\n const byId = new Map<string, LinkEntityOption>()\n rawItems.forEach((record) => {\n if (!record || typeof record !== 'object') return\n const option = normalizeDealRecord(record as Record<string, unknown>)\n if (option) byId.set(option.id, option)\n })\n return uniqueIds.map((id) => byId.get(id) ?? { id, label: id, subtitle: null })\n } catch {\n return uniqueIds.map((id) => ({ id, label: id, subtitle: null }))\n }\n }\n\n const renderRow = (option: LinkEntityOption, ctx: LinkEntityRowContext): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n code?: string | null\n valueAmount?: string | null\n valueCurrency?: string | null\n stage?: string | null\n updatedAt?: string | null\n isOrphan?: boolean\n companyName?: string | null\n }\n const formattedValue = formatValue(meta.valueAmount ?? null, meta.valueCurrency ?? null)\n return (\n <>\n <span className=\"flex size-9 shrink-0 items-center justify-center rounded-md bg-muted/80 text-muted-foreground\">\n <Briefcase className=\"size-4\" />\n </span>\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex min-w-0 flex-wrap items-center gap-1.5\">\n <span className=\"truncate text-sm font-semibold text-foreground\">\n {option.label}\n </span>\n {meta.code ? (\n <span className=\"inline-flex items-center rounded-sm bg-muted px-1.5 py-0.5 text-xs font-semibold uppercase text-muted-foreground\">\n {meta.code}\n </span>\n ) : null}\n {meta.isOrphan ? (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-warning-bg px-2 py-0.5 text-xs font-semibold text-status-warning-text\">\n <span aria-hidden=\"true\" className=\"inline-block size-1.5 rounded-full bg-status-warning-icon\" />\n no company\n </span>\n ) : null}\n </div>\n <div className=\"mt-0.5 flex min-w-0 flex-wrap items-center gap-2 text-xs text-muted-foreground\">\n {formattedValue ? (\n <span className=\"font-semibold text-foreground\">{formattedValue}</span>\n ) : null}\n {meta.stage ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span>{meta.stage}</span>\n </>\n ) : null}\n {meta.companyName ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span className=\"truncate\">{meta.companyName}</span>\n </>\n ) : null}\n {meta.updatedAt ? (\n <>\n <span aria-hidden=\"true\" className=\"inline-block size-1 rounded-full bg-muted-foreground\" />\n <span>{formatRelative(meta.updatedAt)}</span>\n </>\n ) : null}\n </div>\n </div>\n <span\n role=\"checkbox\"\n aria-checked={ctx.selected}\n aria-label={`Select ${option.label}`}\n className={cn(\n 'inline-flex size-5 shrink-0 items-center justify-center rounded-full border',\n ctx.selected\n ? 'border-foreground bg-foreground text-background'\n : 'border-border bg-background',\n )}\n >\n {ctx.selected ? (\n <svg viewBox=\"0 0 12 12\" className=\"size-3\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2.5}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M2.5 6.5l2.5 2.5 4.5-5\" />\n </svg>\n ) : null}\n </span>\n </>\n )\n }\n\n const renderPreview = (\n option: LinkEntityOption,\n details?: DealDetails,\n ): React.ReactNode => {\n const meta = (option.meta ?? {}) as {\n code?: string | null\n valueAmount?: string | null\n valueCurrency?: string | null\n isOrphan?: boolean\n }\n const derived = details ?? {\n id: option.id,\n title: option.label,\n code: meta.code ?? null,\n createdAt: null,\n stage: null,\n value: meta.valueAmount ? { amount: meta.valueAmount, currency: meta.valueCurrency ?? null } : null,\n nextStep: null,\n keyPeople: [],\n anchors: undefined,\n }\n const isOrphan = meta.isOrphan || (derived.anchors ? derived.anchors.companies === 0 : false)\n const formattedValue = derived.value ? formatValue(derived.value.amount, derived.value.currency) : null\n const createdRel = derived.createdAt ? `Created ${formatRelative(derived.createdAt)}` : null\n return (\n <div className=\"flex flex-col gap-3.5 rounded-xl border border-border/70 bg-card p-4\">\n <div>\n <div className=\"text-base font-bold text-foreground\">{derived.title}</div>\n <div className=\"mt-1 flex items-center gap-1.5 text-xs text-muted-foreground\">\n {derived.code ? <span>{derived.code}</span> : null}\n {derived.code && createdRel ? <span>\u00B7</span> : null}\n {createdRel ? <span>{createdRel}</span> : null}\n </div>\n </div>\n\n {isOrphan ? (\n <div className=\"flex items-start gap-2 rounded-md bg-status-warning-bg px-3 py-2.5\">\n <AlertTriangle className=\"mt-0.5 size-3.5 text-status-warning-icon\" />\n <div className=\"min-w-0\">\n <div className=\"text-xs font-semibold text-status-warning-text\">\n {options.orphanWarningTitle}\n </div>\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n {options.orphanWarningMessage}\n </div>\n </div>\n </div>\n ) : null}\n\n {formattedValue ? (\n <div className=\"flex items-baseline gap-3\">\n <div className=\"text-2xl font-bold text-foreground\">{formattedValue}</div>\n <div className=\"text-xs text-muted-foreground\">potential value</div>\n </div>\n ) : null}\n\n {derived.stage ? (\n <>\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Stage\n </div>\n <div className=\"flex items-center gap-1.5\">\n <span className=\"inline-block size-2 rounded-full bg-foreground\" />\n <span className=\"text-xs font-semibold text-foreground\">{derived.stage}</span>\n </div>\n </>\n ) : null}\n\n {derived.nextStep ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Next step\n </div>\n <div className=\"flex items-start gap-2\">\n <CalendarDays className=\"mt-0.5 size-3 text-muted-foreground\" />\n <div className=\"min-w-0\">\n <div className=\"truncate text-xs font-semibold text-foreground\">\n {derived.nextStep.title}\n </div>\n {derived.nextStep.assignee ? (\n <div className=\"mt-0.5 text-xs text-muted-foreground\">\n Assigned: {derived.nextStep.assignee}\n </div>\n ) : null}\n </div>\n </div>\n </>\n ) : null}\n\n {derived.keyPeople && derived.keyPeople.length > 0 ? (\n <>\n <div className=\"h-px w-full bg-border/70\" />\n <div className=\"text-overline font-semibold uppercase tracking-wide text-muted-foreground\">\n Key people ({derived.keyPeople.length})\n </div>\n <div className=\"flex flex-col gap-1.5\">\n {derived.keyPeople.map((person) => (\n <div\n key={person.id || person.name}\n className=\"flex items-center gap-2 rounded-md bg-muted/60 px-2.5 py-1.5\"\n >\n <Avatar label={person.name} variant=\"monochrome\" size=\"sm\" />\n <span className=\"text-xs font-semibold text-foreground\">{person.name}</span>\n {person.role ? (\n <span className=\"ml-auto inline-flex items-center rounded-sm border border-border px-1.5 py-0.5 text-xs font-semibold text-muted-foreground\">\n {person.role}\n </span>\n ) : null}\n </div>\n ))}\n </div>\n </>\n ) : null}\n </div>\n )\n }\n\n const computeOrphanWarning = async (option: LinkEntityOption): Promise<string | null> => {\n const details = await fetchDealDetails(option.id, options.contextEntityId)\n const anchors = details.anchors ?? { companies: 0, people: 0 }\n return anchors.companies + anchors.people < 1 ? options.orphanWarningMessage : null\n }\n\n return {\n kind: 'deal',\n dialogTitle: options.dialogTitle,\n dialogSubtitle: options.dialogSubtitle,\n sectionLabel: options.sectionLabel ?? 'MATCHING DEALS',\n searchPlaceholder: options.searchPlaceholder,\n searchEmptyHint: options.searchEmptyHint,\n selectedEmptyHint: options.selectedEmptyHint,\n confirmButtonLabel: options.confirmButtonLabel,\n defaultAvatarIcon: options.defaultAvatarIcon,\n headerIcon: options.headerIcon ?? <Link2 className=\"size-5\" />,\n filters,\n renderRow,\n renderPreview,\n fetchDetails: (id) => fetchDealDetails(id, options.contextEntityId),\n searchPage,\n fetchByIds,\n computeOrphanWarning,\n addNew: options.addNew,\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/customers/lib/closureStage.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerPipelineStage } from '../data/entities'\n\nexport type DealClosureOutcome = 'won' | 'lost'\n\nexport type PipelineStageSnapshot = {\n id: string\n pipelineId: string\n label: string\n order: number\n}\n\n// Stage labels that mark a pipeline as terminal for a given closure outcome. Matching is\n// label-based because stages are tenant-configurable rows; see #5107.\nexport const TERMINAL_PIPELINE_STAGE_LABELS: Record<DealClosureOutcome, ReadonlySet<string>> = {\n won: new Set(['won', 'win', 'closed won', 'closed win']),\n lost: new Set(['lost', 'loose', 'closed lost', 'closed loose']),\n}\n\n/**\n * Map a deal status spelling (
|
|
5
|
-
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAa/B,MAAM,iCAAkF;AAAA,EAC7F,KAAK,oBAAI,IAAI,CAAC,OAAO,OAAO,cAAc,YAAY,CAAC;AAAA,EACvD,MAAM,oBAAI,IAAI,CAAC,QAAQ,SAAS,eAAe,cAAc,CAAC;AAChE;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { CustomerPipelineStage } from '../data/entities'\n\nexport type DealClosureOutcome = 'won' | 'lost'\n\nexport type PipelineStageSnapshot = {\n id: string\n pipelineId: string\n label: string\n order: number\n}\n\n// Stage labels that mark a pipeline as terminal for a given closure outcome. Matching is\n// label-based because stages are tenant-configurable rows; see #5107.\nexport const TERMINAL_PIPELINE_STAGE_LABELS: Record<DealClosureOutcome, ReadonlySet<string>> = {\n won: new Set(['won', 'win', 'closed won', 'closed win']),\n lost: new Set(['lost', 'loose', 'closed lost', 'closed loose']),\n}\n\n/**\n * Map a deal status spelling (`win`/`lost`, the AI tool's `won`, or the pre-0.7.1\n * `loose`) to its closure\n * outcome. Case-insensitive because callers such as the AI tool pass free-form model\n * text through, while every persisted status is lower-case.\n */\nexport function dealClosureOutcomeFromStatus(status: string | null | undefined): DealClosureOutcome | null {\n const normalized = typeof status === 'string' ? status.trim().toLowerCase() : status\n if (normalized === 'win' || normalized === 'won') return 'won'\n if (normalized === 'loose' || normalized === 'lost') return 'lost'\n return null\n}\n\nexport function normalizePipelineStageLabel(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, ' ')\n .trim()\n}\n\n/**\n * Resolve the terminal stage of the deal's pipeline for a closure outcome, so every\n * writer (command, AI tool preview) agrees on where a closed deal lands (#5107).\n */\nexport async function loadClosurePipelineStageSnapshot(\n em: EntityManager,\n input: {\n pipelineId: string | null\n closureOutcome: DealClosureOutcome\n tenantId: string\n organizationId: string\n },\n): Promise<PipelineStageSnapshot | null> {\n if (!input.pipelineId) return null\n\n const stages = await findWithDecryption(\n em,\n CustomerPipelineStage,\n {\n pipelineId: input.pipelineId,\n tenantId: input.tenantId,\n organizationId: input.organizationId,\n },\n { orderBy: { order: 'ASC' } },\n { tenantId: input.tenantId, organizationId: input.organizationId },\n )\n const aliases = TERMINAL_PIPELINE_STAGE_LABELS[input.closureOutcome]\n const stage = stages.find((candidate) => aliases.has(normalizePipelineStageLabel(candidate.label)))\n if (!stage) return null\n return {\n id: stage.id,\n pipelineId: stage.pipelineId,\n label: stage.label,\n order: stage.order,\n }\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AAa/B,MAAM,iCAAkF;AAAA,EAC7F,KAAK,oBAAI,IAAI,CAAC,OAAO,OAAO,cAAc,YAAY,CAAC;AAAA,EACvD,MAAM,oBAAI,IAAI,CAAC,QAAQ,SAAS,eAAe,cAAc,CAAC;AAChE;AAQO,SAAS,6BAA6B,QAA8D;AACzG,QAAM,aAAa,OAAO,WAAW,WAAW,OAAO,KAAK,EAAE,YAAY,IAAI;AAC9E,MAAI,eAAe,SAAS,eAAe,MAAO,QAAO;AACzD,MAAI,eAAe,WAAW,eAAe,OAAQ,QAAO;AAC5D,SAAO;AACT;AAEO,SAAS,4BAA4B,OAAuB;AACjE,SAAO,MACJ,KAAK,EACL,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,KAAK;AACV;AAMA,eAAsB,iCACpB,IACA,OAMuC;AACvC,MAAI,CAAC,MAAM,WAAY,QAAO;AAE9B,QAAM,SAAS,MAAM;AAAA,IACnB;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,MAAM;AAAA,MAClB,UAAU,MAAM;AAAA,MAChB,gBAAgB,MAAM;AAAA,IACxB;AAAA,IACA,EAAE,SAAS,EAAE,OAAO,MAAM,EAAE;AAAA,IAC5B,EAAE,UAAU,MAAM,UAAU,gBAAgB,MAAM,eAAe;AAAA,EACnE;AACA,QAAM,UAAU,+BAA+B,MAAM,cAAc;AACnE,QAAM,QAAQ,OAAO,KAAK,CAAC,cAAc,QAAQ,IAAI,4BAA4B,UAAU,KAAK,CAAC,CAAC;AAClG,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,YAAY,MAAM;AAAA,IAClB,OAAO,MAAM;AAAA,IACb,OAAO,MAAM;AAAA,EACf;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|