@open-mercato/core 0.6.7-develop.6568.1.9f57ffc393 → 0.6.7-develop.6572.1.3d8e83062f

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.
@@ -215,7 +215,7 @@ const createOrganizationCommand = {
215
215
  async execute(rawInput, ctx) {
216
216
  const { parsed, custom } = parseWithCustomFields(organizationCreateSchema, rawInput);
217
217
  const em = ctx.container.resolve("em");
218
- const tenantId = await enforceTenantSelection(ctx, parsed.tenantId ?? null);
218
+ const tenantId = await enforceTenantSelection(ctx, parsed.tenantId);
219
219
  if (!tenantId) throw new CrudHttpError(400, { error: "Tenant scope required" });
220
220
  const parentId = parsed.parentId ?? null;
221
221
  if (parentId) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/directory/commands/organizations.ts"],
4
- "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { Organization, Tenant } from '@open-mercato/core/modules/directory/data/entities'\nimport { organizationCreateSchema, organizationUpdateSchema } from '@open-mercato/core/modules/directory/data/validators'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { enforceTenantSelection } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { E } from '#generated/entities.ids.generated'\nimport type { CrudEmitContext, CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n diffCustomFieldChanges,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n buildChanges,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { toOptionalString } from '@open-mercato/shared/lib/string/coerce'\nimport { slugify } from '@open-mercato/shared/lib/slugify'\n\nexport const organizationCrudEvents: CrudEventsConfig = {\n module: 'directory',\n entity: 'organization',\n persistent: true,\n buildPayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n id: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n organizationId: orgCtx.identifiers.id,\n }\n },\n}\n\nexport const organizationCrudIndexer: CrudIndexerConfig = {\n entityType: E.directory.organization,\n buildUpsertPayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n entityType: E.directory.organization,\n recordId: orgCtx.identifiers.id,\n organizationId: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n }\n },\n buildDeletePayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n entityType: E.directory.organization,\n recordId: orgCtx.identifiers.id,\n organizationId: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n }\n },\n}\n\ntype OrganizationTenantShape = {\n __tenantId?: unknown\n tenant?: string | { id?: unknown; getEntity?: () => { id?: unknown } }\n tenantId?: unknown\n tenant_id?: unknown\n}\n\ntype SerializedOrganization = ReturnType<typeof serializeOrganization>\n\ntype ChildParentSnapshot = {\n childId: string\n parentId: string | null\n}\n\ntype OrganizationUndoSnapshot = {\n id: string\n tenantId: string | null\n name: string\n slug?: string | null\n logoUrl?: string | null\n isActive: boolean\n parentId: string | null\n childParents: ChildParentSnapshot[]\n custom?: Record<string, unknown>\n}\n\ntype OrganizationSnapshots = {\n view: SerializedOrganization\n undo: OrganizationUndoSnapshot\n}\n\nexport function resolveTenantIdFromEntity(entity: Organization): string | null {\n const shape = entity as unknown as OrganizationTenantShape\n const cached = toOptionalString(shape.__tenantId)\n if (cached) return cached\n const tenantRef = shape.tenant\n if (typeof tenantRef === 'string') return tenantRef\n if (tenantRef && typeof tenantRef === 'object') {\n const direct = toOptionalString(tenantRef.id)\n if (direct) return direct\n if (typeof tenantRef.getEntity === 'function') {\n const nested = tenantRef.getEntity()\n const nestedId = nested ? toOptionalString(nested.id) : null\n if (nestedId) return nestedId\n }\n }\n const fallback = toOptionalString(shape.tenantId) || toOptionalString(shape.tenant_id)\n return fallback\n}\n\nfunction serializeOrganization(entity: Organization, custom?: Record<string, unknown> | null) {\n return {\n id: String(entity.id),\n tenantId: resolveTenantIdFromEntity(entity),\n name: entity.name,\n slug: entity.slug ?? null,\n logoUrl: entity.logoUrl ?? null,\n isActive: !!entity.isActive,\n parentId: entity.parentId ?? null,\n ancestorIds: Array.isArray(entity.ancestorIds) ? [...entity.ancestorIds] : [],\n childIds: Array.isArray(entity.childIds) ? [...entity.childIds] : [],\n descendantIds: Array.isArray(entity.descendantIds) ? [...entity.descendantIds] : [],\n createdAt: entity.createdAt ? entity.createdAt.toISOString() : null,\n updatedAt: entity.updatedAt ? entity.updatedAt.toISOString() : null,\n ...(custom && Object.keys(custom).length ? { custom } : {}),\n }\n}\n\nfunction captureOrganizationSnapshots(\n entity: Organization,\n childParents: ChildParentSnapshot[],\n custom?: Record<string, unknown> | null\n): OrganizationSnapshots {\n const tenantId = resolveTenantIdFromEntity(entity)\n return {\n view: serializeOrganization(entity, custom),\n undo: {\n id: String(entity.id),\n tenantId,\n name: entity.name,\n slug: entity.slug ?? null,\n logoUrl: entity.logoUrl ?? null,\n isActive: !!entity.isActive,\n parentId: entity.parentId ?? null,\n childParents: (childParents ?? []).map((entry) => ({\n childId: String(entry.childId),\n parentId: entry.parentId,\n })),\n ...(custom && Object.keys(custom).length ? { custom } : {}),\n },\n }\n}\n\nasync function loadChildParentSnapshots(\n em: EntityManager,\n tenantId: string | null,\n childIds: Iterable<string>\n): Promise<ChildParentSnapshot[]> {\n if (!tenantId) return []\n const ids = Array.from(new Set(Array.from(childIds ?? []).map((id) => String(id)).filter(Boolean)))\n if (!ids.length) return []\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: ids },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, filter)\n if (!children.length) return []\n const map = new Map(children.map((child) => [String(child.id), child.parentId ? String(child.parentId) : null]))\n return ids\n .filter((id) => map.has(id))\n .map((id) => ({\n childId: id,\n parentId: map.get(id) ?? null,\n }))\n}\n\nasync function restoreChildParents(em: EntityManager, tenantId: string, snapshots: ChildParentSnapshot[]) {\n if (!snapshots?.length) return\n const ids = Array.from(new Set(snapshots.map((entry) => entry.childId).filter(Boolean)))\n if (!ids.length) return\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: ids },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, filter)\n if (!children.length) return\n const desired = new Map(snapshots.map((entry) => [entry.childId, entry.parentId ?? null]))\n const toPersist: Organization[] = []\n for (const child of children) {\n const id = String(child.id)\n if (!desired.has(id)) continue\n const nextParent = desired.get(id) ?? null\n if (child.parentId !== nextParent) {\n child.parentId = nextParent\n toPersist.push(child)\n }\n }\n if (toPersist.length) await em.persist(toPersist).flush()\n}\n\nfunction normalizeChildIds(ids: readonly string[], exclude: string[]): string[] {\n const excludeSet = new Set(exclude)\n return Array.from(new Set(ids)).filter((id) => !excludeSet.has(id))\n}\n\nasync function ensureParentExists(em: EntityManager, tenantId: string, parentId: string | null): Promise<void> {\n if (!parentId) return\n const parentFilter: FilterQuery<Organization> = { id: parentId, tenant: tenantId, deletedAt: null }\n const parent = await em.findOne(Organization, parentFilter)\n if (!parent) throw new CrudHttpError(400, { error: 'Parent not found' })\n}\n\nasync function ensureChildrenValid(em: EntityManager, tenantId: string, childIds: string[]): Promise<void> {\n if (!childIds.length) return\n const childFilter: FilterQuery<Organization> = { id: { $in: childIds }, tenant: tenantId, deletedAt: null }\n const children = await em.find(Organization, childFilter)\n if (children.length !== childIds.length) throw new CrudHttpError(400, { error: 'Invalid child assignment' })\n}\n\nasync function assignChildren(\n em: EntityManager,\n tenantId: string,\n recordId: string,\n desiredChildIds: Iterable<string>\n): Promise<void> {\n const targetIds = Array.from(new Set(desiredChildIds)).filter((id) => id !== recordId)\n if (!targetIds.length) return\n const filter: FilterQuery<Organization> = { tenant: tenantId, deletedAt: null, id: { $in: targetIds } }\n const children = await em.find(Organization, filter)\n const toPersist: Organization[] = []\n for (const child of children) {\n if (String(child.id) === recordId) continue\n if (child.parentId !== recordId) {\n child.parentId = recordId\n toPersist.push(child)\n }\n }\n if (toPersist.length) await em.persist(toPersist).flush()\n}\n\nasync function clearRemovedChildren(em: EntityManager, tenantId: string, recordId: string, desiredChildIds: Set<string>): Promise<void> {\n const currentFilter: FilterQuery<Organization> = { tenant: tenantId, parentId: recordId, deletedAt: null }\n const current = await em.find(Organization, currentFilter)\n const toPersist = current.filter((child) => !desiredChildIds.has(String(child.id)))\n if (!toPersist.length) return\n for (const child of toPersist) child.parentId = null\n await em.persist(toPersist).flush()\n}\n\nasync function resolveUniqueSlug(em: EntityManager, tenantId: string, baseSlug: string, excludeId?: string): Promise<string> {\n let candidate = baseSlug\n let suffix = 0\n const maxAttempts = 50\n while (suffix < maxAttempts) {\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n slug: candidate,\n deletedAt: null,\n } as unknown as FilterQuery<Organization>\n const existing = await em.findOne(Organization, filter)\n if (!existing || (excludeId && String(existing.id) === excludeId)) return candidate\n suffix += 1\n candidate = `${baseSlug}-${suffix}`\n }\n return `${baseSlug}-${Date.now()}`\n}\n\nconst createOrganizationCommand: CommandHandler<Record<string, unknown>, Organization> = {\n id: 'directory.organizations.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(organizationCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const tenantId = await enforceTenantSelection(ctx, parsed.tenantId ?? null)\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = parsed.parentId ?? null\n if (parentId) {\n await ensureParentExists(em, tenantId, parentId)\n }\n\n const childIds = normalizeChildIds(parsed.childIds ?? [], parentId ? [parentId] : [])\n if (parentId && childIds.includes(parentId)) throw new CrudHttpError(400, { error: 'Child cannot equal parent' })\n await ensureChildrenValid(em, tenantId, childIds)\n const childParentsBefore = await loadChildParentSnapshots(em, tenantId, childIds)\n\n const tenantRef = em.getReference(Tenant, tenantId)\n const baseSlug = parsed.slug ? parsed.slug : slugify(parsed.name)\n const slug = baseSlug ? await resolveUniqueSlug(em, tenantId, baseSlug) : null\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let organization!: Organization\n await withAtomicFlush(em, [\n async () => {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n tenant: tenantRef,\n name: parsed.name,\n slug,\n logoUrl: parsed.logoUrl ?? null,\n isActive: parsed.isActive ?? true,\n parentId,\n },\n })\n setInternalTenantId(organization, tenantId)\n const recordId = String(organization.id)\n\n if (childIds.length) {\n await assignChildren(em, tenantId, recordId, childIds)\n }\n const childParentsAfter = await loadChildParentSnapshots(em, tenantId, childIds)\n setUndoMeta(organization, { childParentsBefore, childParentsAfter })\n\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: E.directory.organization,\n recordId,\n tenantId,\n organizationId: recordId,\n values: custom,\n })\n\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const recordId = String(organization.id)\n const identifiers = { id: recordId, organizationId: recordId, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: organization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return organization\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n return serializeOrganization(result, custom)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const meta = getUndoMeta(result)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n const afterSnapshots = captureOrganizationSnapshots(result, meta.childParentsAfter ?? [], custom)\n return {\n actionLabel: translate('directory.audit.organizations.create', 'Create organization'),\n resourceKind: 'directory.organization',\n resourceId: String(result.id),\n tenantId: ctx.auth?.tenantId ?? resolveTenantIdFromEntity(result),\n snapshotAfter: afterSnapshots.view,\n payload: {\n undo: {\n after: afterSnapshots.undo,\n childrenBefore: meta.childParentsBefore ?? [],\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const after = payload?.after\n const childrenBefore = payload?.childrenBefore ?? []\n if (!after) return\n const tenantId = after.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await withAtomicFlush(em, [\n async () => {\n await restoreChildParents(em, tenantId, childrenBefore)\n if (after.custom && Object.keys(after.custom).length) {\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: after.id,\n tenantId,\n organizationId: after.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n await de.deleteOrmEntity({\n entity: Organization,\n where: { id: after.id, deletedAt: null } as FilterQuery<Organization>,\n soft: false,\n })\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<OrganizationUndoSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for organization create' })\n const tenantId = after.tenantId\n if (!tenantId) throw new CrudHttpError(400, { error: '[internal] redo snapshot missing tenant for organization create' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let organization!: Organization\n await withAtomicFlush(em, [\n async () => {\n const existing = await em.findOne(Organization, { id: after.id })\n if (existing) {\n existing.deletedAt = null\n existing.name = after.name\n if (after.slug !== undefined) existing.slug = after.slug ?? null\n if (after.logoUrl !== undefined) existing.logoUrl = after.logoUrl ?? null\n existing.isActive = after.isActive\n existing.parentId = after.parentId\n await em.flush()\n organization = existing\n } else {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n id: after.id,\n name: after.name,\n slug: after.slug ?? null,\n logoUrl: after.logoUrl ?? null,\n tenant: em.getReference(Tenant, tenantId),\n isActive: after.isActive,\n parentId: after.parentId,\n },\n })\n }\n setInternalTenantId(organization, tenantId)\n\n if (after.custom && Object.keys(after.custom).length) {\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: after.id,\n tenantId,\n organizationId: after.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n\n await assignChildren(em, tenantId, after.id, after.childParents.map((entry) => entry.childId))\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const identifiers = { id: after.id, organizationId: after.id, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: organization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return organization\n },\n}\n\nconst updateOrganizationCommand: CommandHandler<Record<string, unknown>, Organization> = {\n id: 'directory.organizations.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(organizationUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const current = await em.findOne(Organization, { id: parsed.id, deletedAt: null })\n if (!current) throw new CrudHttpError(404, { error: 'Not found' })\n const tenantId = resolveTenantIdFromEntity(current)\n const currentChildIds = Array.isArray(current.childIds) ? current.childIds : []\n const requestedChildIds = Array.isArray(parsed.childIds) ? parsed.childIds : []\n const combinedChildIds = new Set<string>([...currentChildIds.map(String), ...requestedChildIds.map(String)])\n const childParentsBefore = tenantId\n ? await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n : []\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(current.id),\n tenantId,\n organizationId: String(current.id),\n })\n return { before: captureOrganizationSnapshots(current, childParentsBefore, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(organizationUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id: parsed.id, deletedAt: null })\n if (!existing) throw new CrudHttpError(404, { error: 'Not found' })\n\n const tenantId = await enforceTenantSelection(ctx, parsed.tenantId ?? resolveTenantIdFromEntity(existing))\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = parsed.parentId ?? null\n if (parentId) {\n if (parentId === parsed.id) throw new CrudHttpError(400, { error: 'Organization cannot be its own parent' })\n if (Array.isArray(existing.descendantIds) && existing.descendantIds.includes(parentId)) {\n throw new CrudHttpError(400, { error: 'Cannot assign descendant as parent' })\n }\n await ensureParentExists(em, tenantId, parentId)\n }\n\n const normalizedChildIds = normalizeChildIds(parsed.childIds ?? [], [parsed.id, parentId ?? ''])\n if (normalizedChildIds.some((id) => id === parentId)) throw new CrudHttpError(400, { error: 'Child cannot equal parent' })\n if (Array.isArray(existing.ancestorIds) && normalizedChildIds.some((id) => existing.ancestorIds.includes(id))) {\n throw new CrudHttpError(400, { error: 'Cannot assign ancestor as child' })\n }\n\n if (normalizedChildIds.length) {\n await ensureChildrenValid(em, tenantId, normalizedChildIds)\n const childFilter = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: normalizedChildIds },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, childFilter)\n for (const child of children) {\n if (Array.isArray(child.descendantIds) && child.descendantIds.includes(parsed.id)) {\n throw new CrudHttpError(400, { error: 'Cannot assign descendant cycle' })\n }\n }\n }\n\n const combinedChildIds = new Set<string>([\n ...normalizedChildIds.map(String),\n ...(Array.isArray(existing.childIds) ? existing.childIds.map(String) : []),\n ])\n const childParentsBefore = await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n\n let resolvedSlug: string | null | undefined\n if (parsed.slug !== undefined) {\n resolvedSlug = parsed.slug ? await resolveUniqueSlug(em, tenantId, parsed.slug, parsed.id) : parsed.slug\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let resolvedOrganization!: Organization\n await withAtomicFlush(em, [\n async () => {\n const organization = await de.updateOrmEntity({\n entity: Organization,\n where: { id: parsed.id, deletedAt: null } as FilterQuery<Organization>,\n apply: (entity) => {\n if (parsed.name !== undefined) entity.name = parsed.name\n if (resolvedSlug !== undefined) entity.slug = resolvedSlug\n if (parsed.logoUrl !== undefined) entity.logoUrl = parsed.logoUrl ?? null\n if (parsed.isActive !== undefined) entity.isActive = parsed.isActive\n entity.parentId = parentId\n },\n })\n if (!organization) throw new CrudHttpError(404, { error: 'Not found' })\n setInternalTenantId(organization, tenantId)\n\n const recordId = String(organization.id)\n const desiredChildIds = new Set(normalizedChildIds.filter((id) => id !== recordId))\n await clearRemovedChildren(em, tenantId, recordId, desiredChildIds)\n await assignChildren(em, tenantId, recordId, desiredChildIds)\n const childParentsAfter = await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n setUndoMeta(organization, { childParentsBefore, childParentsAfter })\n\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: E.directory.organization,\n recordId,\n tenantId,\n organizationId: recordId,\n values: custom,\n })\n\n await rebuildHierarchyForTenant(em, tenantId)\n resolvedOrganization = organization\n },\n ], { transaction: true })\n\n const recordId = String(resolvedOrganization.id)\n const identifiers = { id: recordId, organizationId: recordId, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: resolvedOrganization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return resolvedOrganization\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n return serializeOrganization(result, custom)\n },\n buildLog: async ({ snapshots, result, ctx }) => {\n const { translate } = await resolveTranslations()\n const meta = getUndoMeta(result)\n const beforeSnapshots = snapshots.before as OrganizationSnapshots | undefined\n const beforeRecord = beforeSnapshots?.view ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n const after = serializeOrganization(result, custom)\n const changes = buildChanges(beforeRecord, after as Record<string, unknown>, ['name', 'slug', 'logoUrl', 'isActive', 'parentId'])\n const customDiff = diffCustomFieldChanges(beforeRecord?.custom, custom)\n for (const [key, diff] of Object.entries(customDiff)) {\n changes[`cf_${key}`] = diff\n }\n return {\n actionLabel: translate('directory.audit.organizations.update', 'Update organization'),\n resourceKind: 'directory.organization',\n resourceId: String(result.id),\n changes,\n tenantId: ctx.auth?.tenantId ?? after.tenantId,\n payload: {\n undo: {\n before: beforeSnapshots?.undo ?? null,\n after: captureOrganizationSnapshots(result, meta.childParentsAfter ?? [], custom).undo,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const before = payload?.before\n const after = payload?.after\n if (!before) return\n const tenantId = before.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let updated: Organization | null = null\n await withAtomicFlush(em, [\n async () => {\n updated = await de.updateOrmEntity({\n entity: Organization,\n where: { id: before.id } as FilterQuery<Organization>,\n apply: (entity) => {\n entity.name = before.name\n if (before.slug !== undefined) entity.slug = before.slug\n if (before.logoUrl !== undefined) entity.logoUrl = before.logoUrl ?? null\n entity.isActive = before.isActive\n entity.parentId = before.parentId\n },\n })\n if (updated && tenantId) {\n setInternalTenantId(updated, tenantId)\n }\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: before.id,\n tenantId,\n organizationId: before.id,\n values: resetValues,\n notify: false,\n })\n }\n const childSnapshots = before.childParents\n await restoreChildParents(em, tenantId, childSnapshots)\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: updated,\n identifiers: {\n id: before.id,\n tenantId,\n organizationId: before.id,\n },\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n },\n}\n\nconst deleteOrganizationCommand: CommandHandler<{ body: any; query: Record<string, string> }, Organization> = {\n id: 'directory.organizations.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Organization id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id, deletedAt: null })\n if (!existing) return {}\n const tenantId = resolveTenantIdFromEntity(existing)\n const childParentsBefore = tenantId\n ? await loadChildParentSnapshots(em, tenantId, Array.isArray(existing.childIds) ? existing.childIds : [])\n : []\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(existing.id),\n tenantId,\n organizationId: String(existing.id),\n })\n return { before: captureOrganizationSnapshots(existing, childParentsBefore, custom) }\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Organization id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id, deletedAt: null })\n if (!existing) throw new CrudHttpError(404, { error: 'Not found' })\n\n const tenantId = await enforceTenantSelection(ctx, resolveTenantIdFromEntity(existing))\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = existing.parentId ?? null\n const childSnapshotsBefore = await loadChildParentSnapshots(\n em,\n tenantId,\n Array.isArray(existing.childIds) ? existing.childIds : [],\n )\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let resolvedDeleted!: Organization\n await withAtomicFlush(em, [\n async () => {\n const deleted = await de.deleteOrmEntity({\n entity: Organization,\n where: { id, deletedAt: null } as FilterQuery<Organization>,\n soft: true,\n softDeleteField: 'deletedAt',\n })\n if (!deleted) throw new CrudHttpError(404, { error: 'Not found' })\n setInternalTenantId(deleted, tenantId)\n deleted.isActive = false\n deleted.parentId = null\n resolvedDeleted = deleted\n },\n async () => {\n const deleted = resolvedDeleted\n const childrenFilter: FilterQuery<Organization> = { tenant: tenantId, parentId: id, deletedAt: null }\n const children = await em.find(Organization, childrenFilter)\n const toPersist: Organization[] = []\n for (const child of children) {\n child.parentId = parentId\n toPersist.push(child)\n }\n toPersist.push(deleted)\n if (toPersist.length) em.persist(toPersist)\n setUndoMeta(deleted, { childParentsBefore: childSnapshotsBefore })\n },\n async () => {\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const identifiers = { id, organizationId: id, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: resolvedDeleted,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return resolvedDeleted\n },\n buildLog: async ({ snapshots, input, ctx }) => {\n const { translate } = await resolveTranslations()\n const beforeSnapshots = snapshots.before as OrganizationSnapshots | undefined\n const beforeSnapshot = beforeSnapshots?.view ?? null\n const beforeUndo = beforeSnapshots?.undo ?? null\n const id = String(input?.body?.id ?? input?.query?.id ?? '')\n const fallbackId = beforeSnapshot?.id ?? null\n const fallbackTenant = beforeSnapshot?.tenantId ?? null\n return {\n actionLabel: translate('directory.audit.organizations.delete', 'Delete organization'),\n resourceKind: 'directory.organization',\n resourceId: id || fallbackId || null,\n snapshotBefore: beforeSnapshot ?? null,\n tenantId: ctx.auth?.tenantId ?? fallbackTenant,\n payload: {\n undo: {\n before: beforeUndo,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const tenantId = before.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let organization: Organization | null = null\n await withAtomicFlush(em, [\n async () => {\n organization = await em.findOne(Organization, { id: before.id })\n if (organization) {\n organization.deletedAt = null\n organization.isActive = before.isActive\n organization.name = before.name\n if (before.slug !== undefined) organization.slug = before.slug\n organization.parentId = before.parentId\n await em.flush()\n if (tenantId) setInternalTenantId(organization, tenantId)\n } else {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n id: before.id,\n name: before.name,\n slug: before.slug ?? null,\n tenant: tenantId ? em.getReference(Tenant, tenantId) : undefined,\n isActive: before.isActive,\n parentId: before.parentId,\n },\n })\n if (tenantId) setInternalTenantId(organization, tenantId)\n }\n if (tenantId) {\n const customValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(customValues).length) {\n const resetValues = customValues as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: before.id,\n tenantId,\n organizationId: before.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n await restoreChildParents(em, tenantId, before.childParents)\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: organization,\n identifiers: {\n id: before.id,\n tenantId,\n organizationId: before.id,\n },\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n },\n}\n\ntype OrganizationUndoPayload = {\n before?: OrganizationUndoSnapshot | null\n after?: OrganizationUndoSnapshot | null\n childrenBefore?: ChildParentSnapshot[] | null\n}\n\ntype OrganizationUndoMeta = {\n childParentsBefore?: ChildParentSnapshot[]\n childParentsAfter?: ChildParentSnapshot[]\n}\n\nconst UNDO_META_KEY: unique symbol = Symbol('directory.organization.undoMeta')\n\nfunction getUndoMeta(entity: Organization): OrganizationUndoMeta {\n return (Reflect.get(entity, UNDO_META_KEY) as OrganizationUndoMeta | undefined) ?? {}\n}\n\nfunction setUndoMeta(entity: Organization, meta: Partial<OrganizationUndoMeta>) {\n const current = getUndoMeta(entity)\n Reflect.set(entity, UNDO_META_KEY, { ...current, ...meta })\n}\n\nregisterCommand(createOrganizationCommand)\nregisterCommand(updateOrganizationCommand)\nregisterCommand(deleteOrganizationCommand)\n\nfunction setInternalTenantId(entity: Organization, tenantId: string) {\n Reflect.set(entity, '__tenantId', tenantId)\n}\n\nfunction tenantIdFromContext(ctx: CrudEmitContext<Organization>): string | null {\n return resolveTenantIdFromEntity(ctx.entity) ?? ctx.identifiers.tenantId ?? null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport type { EntityManager, FilterQuery } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { Organization, Tenant } from '@open-mercato/core/modules/directory/data/entities'\nimport { organizationCreateSchema, organizationUpdateSchema } from '@open-mercato/core/modules/directory/data/validators'\nimport { rebuildHierarchyForTenant } from '@open-mercato/core/modules/directory/lib/hierarchy'\nimport { enforceTenantSelection } from '@open-mercato/core/modules/auth/lib/tenantAccess'\nimport { E } from '#generated/entities.ids.generated'\nimport type { CrudEmitContext, CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport {\n loadCustomFieldSnapshot,\n buildCustomFieldResetMap,\n diffCustomFieldChanges,\n} from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { extractUndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport {\n parseWithCustomFields,\n setCustomFieldsIfAny,\n emitCrudSideEffects,\n emitCrudUndoSideEffects,\n requireId,\n buildChanges,\n} from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { toOptionalString } from '@open-mercato/shared/lib/string/coerce'\nimport { slugify } from '@open-mercato/shared/lib/slugify'\n\nexport const organizationCrudEvents: CrudEventsConfig = {\n module: 'directory',\n entity: 'organization',\n persistent: true,\n buildPayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n id: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n organizationId: orgCtx.identifiers.id,\n }\n },\n}\n\nexport const organizationCrudIndexer: CrudIndexerConfig = {\n entityType: E.directory.organization,\n buildUpsertPayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n entityType: E.directory.organization,\n recordId: orgCtx.identifiers.id,\n organizationId: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n }\n },\n buildDeletePayload: (ctx) => {\n const orgCtx = ctx as CrudEmitContext<Organization>\n return {\n entityType: E.directory.organization,\n recordId: orgCtx.identifiers.id,\n organizationId: orgCtx.identifiers.id,\n tenantId: tenantIdFromContext(orgCtx),\n }\n },\n}\n\ntype OrganizationTenantShape = {\n __tenantId?: unknown\n tenant?: string | { id?: unknown; getEntity?: () => { id?: unknown } }\n tenantId?: unknown\n tenant_id?: unknown\n}\n\ntype SerializedOrganization = ReturnType<typeof serializeOrganization>\n\ntype ChildParentSnapshot = {\n childId: string\n parentId: string | null\n}\n\ntype OrganizationUndoSnapshot = {\n id: string\n tenantId: string | null\n name: string\n slug?: string | null\n logoUrl?: string | null\n isActive: boolean\n parentId: string | null\n childParents: ChildParentSnapshot[]\n custom?: Record<string, unknown>\n}\n\ntype OrganizationSnapshots = {\n view: SerializedOrganization\n undo: OrganizationUndoSnapshot\n}\n\nexport function resolveTenantIdFromEntity(entity: Organization): string | null {\n const shape = entity as unknown as OrganizationTenantShape\n const cached = toOptionalString(shape.__tenantId)\n if (cached) return cached\n const tenantRef = shape.tenant\n if (typeof tenantRef === 'string') return tenantRef\n if (tenantRef && typeof tenantRef === 'object') {\n const direct = toOptionalString(tenantRef.id)\n if (direct) return direct\n if (typeof tenantRef.getEntity === 'function') {\n const nested = tenantRef.getEntity()\n const nestedId = nested ? toOptionalString(nested.id) : null\n if (nestedId) return nestedId\n }\n }\n const fallback = toOptionalString(shape.tenantId) || toOptionalString(shape.tenant_id)\n return fallback\n}\n\nfunction serializeOrganization(entity: Organization, custom?: Record<string, unknown> | null) {\n return {\n id: String(entity.id),\n tenantId: resolveTenantIdFromEntity(entity),\n name: entity.name,\n slug: entity.slug ?? null,\n logoUrl: entity.logoUrl ?? null,\n isActive: !!entity.isActive,\n parentId: entity.parentId ?? null,\n ancestorIds: Array.isArray(entity.ancestorIds) ? [...entity.ancestorIds] : [],\n childIds: Array.isArray(entity.childIds) ? [...entity.childIds] : [],\n descendantIds: Array.isArray(entity.descendantIds) ? [...entity.descendantIds] : [],\n createdAt: entity.createdAt ? entity.createdAt.toISOString() : null,\n updatedAt: entity.updatedAt ? entity.updatedAt.toISOString() : null,\n ...(custom && Object.keys(custom).length ? { custom } : {}),\n }\n}\n\nfunction captureOrganizationSnapshots(\n entity: Organization,\n childParents: ChildParentSnapshot[],\n custom?: Record<string, unknown> | null\n): OrganizationSnapshots {\n const tenantId = resolveTenantIdFromEntity(entity)\n return {\n view: serializeOrganization(entity, custom),\n undo: {\n id: String(entity.id),\n tenantId,\n name: entity.name,\n slug: entity.slug ?? null,\n logoUrl: entity.logoUrl ?? null,\n isActive: !!entity.isActive,\n parentId: entity.parentId ?? null,\n childParents: (childParents ?? []).map((entry) => ({\n childId: String(entry.childId),\n parentId: entry.parentId,\n })),\n ...(custom && Object.keys(custom).length ? { custom } : {}),\n },\n }\n}\n\nasync function loadChildParentSnapshots(\n em: EntityManager,\n tenantId: string | null,\n childIds: Iterable<string>\n): Promise<ChildParentSnapshot[]> {\n if (!tenantId) return []\n const ids = Array.from(new Set(Array.from(childIds ?? []).map((id) => String(id)).filter(Boolean)))\n if (!ids.length) return []\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: ids },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, filter)\n if (!children.length) return []\n const map = new Map(children.map((child) => [String(child.id), child.parentId ? String(child.parentId) : null]))\n return ids\n .filter((id) => map.has(id))\n .map((id) => ({\n childId: id,\n parentId: map.get(id) ?? null,\n }))\n}\n\nasync function restoreChildParents(em: EntityManager, tenantId: string, snapshots: ChildParentSnapshot[]) {\n if (!snapshots?.length) return\n const ids = Array.from(new Set(snapshots.map((entry) => entry.childId).filter(Boolean)))\n if (!ids.length) return\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: ids },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, filter)\n if (!children.length) return\n const desired = new Map(snapshots.map((entry) => [entry.childId, entry.parentId ?? null]))\n const toPersist: Organization[] = []\n for (const child of children) {\n const id = String(child.id)\n if (!desired.has(id)) continue\n const nextParent = desired.get(id) ?? null\n if (child.parentId !== nextParent) {\n child.parentId = nextParent\n toPersist.push(child)\n }\n }\n if (toPersist.length) await em.persist(toPersist).flush()\n}\n\nfunction normalizeChildIds(ids: readonly string[], exclude: string[]): string[] {\n const excludeSet = new Set(exclude)\n return Array.from(new Set(ids)).filter((id) => !excludeSet.has(id))\n}\n\nasync function ensureParentExists(em: EntityManager, tenantId: string, parentId: string | null): Promise<void> {\n if (!parentId) return\n const parentFilter: FilterQuery<Organization> = { id: parentId, tenant: tenantId, deletedAt: null }\n const parent = await em.findOne(Organization, parentFilter)\n if (!parent) throw new CrudHttpError(400, { error: 'Parent not found' })\n}\n\nasync function ensureChildrenValid(em: EntityManager, tenantId: string, childIds: string[]): Promise<void> {\n if (!childIds.length) return\n const childFilter: FilterQuery<Organization> = { id: { $in: childIds }, tenant: tenantId, deletedAt: null }\n const children = await em.find(Organization, childFilter)\n if (children.length !== childIds.length) throw new CrudHttpError(400, { error: 'Invalid child assignment' })\n}\n\nasync function assignChildren(\n em: EntityManager,\n tenantId: string,\n recordId: string,\n desiredChildIds: Iterable<string>\n): Promise<void> {\n const targetIds = Array.from(new Set(desiredChildIds)).filter((id) => id !== recordId)\n if (!targetIds.length) return\n const filter: FilterQuery<Organization> = { tenant: tenantId, deletedAt: null, id: { $in: targetIds } }\n const children = await em.find(Organization, filter)\n const toPersist: Organization[] = []\n for (const child of children) {\n if (String(child.id) === recordId) continue\n if (child.parentId !== recordId) {\n child.parentId = recordId\n toPersist.push(child)\n }\n }\n if (toPersist.length) await em.persist(toPersist).flush()\n}\n\nasync function clearRemovedChildren(em: EntityManager, tenantId: string, recordId: string, desiredChildIds: Set<string>): Promise<void> {\n const currentFilter: FilterQuery<Organization> = { tenant: tenantId, parentId: recordId, deletedAt: null }\n const current = await em.find(Organization, currentFilter)\n const toPersist = current.filter((child) => !desiredChildIds.has(String(child.id)))\n if (!toPersist.length) return\n for (const child of toPersist) child.parentId = null\n await em.persist(toPersist).flush()\n}\n\nasync function resolveUniqueSlug(em: EntityManager, tenantId: string, baseSlug: string, excludeId?: string): Promise<string> {\n let candidate = baseSlug\n let suffix = 0\n const maxAttempts = 50\n while (suffix < maxAttempts) {\n const filter: FilterQuery<Organization> = {\n tenant: tenantId,\n slug: candidate,\n deletedAt: null,\n } as unknown as FilterQuery<Organization>\n const existing = await em.findOne(Organization, filter)\n if (!existing || (excludeId && String(existing.id) === excludeId)) return candidate\n suffix += 1\n candidate = `${baseSlug}-${suffix}`\n }\n return `${baseSlug}-${Date.now()}`\n}\n\nconst createOrganizationCommand: CommandHandler<Record<string, unknown>, Organization> = {\n id: 'directory.organizations.create',\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(organizationCreateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const tenantId = await enforceTenantSelection(ctx, parsed.tenantId)\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = parsed.parentId ?? null\n if (parentId) {\n await ensureParentExists(em, tenantId, parentId)\n }\n\n const childIds = normalizeChildIds(parsed.childIds ?? [], parentId ? [parentId] : [])\n if (parentId && childIds.includes(parentId)) throw new CrudHttpError(400, { error: 'Child cannot equal parent' })\n await ensureChildrenValid(em, tenantId, childIds)\n const childParentsBefore = await loadChildParentSnapshots(em, tenantId, childIds)\n\n const tenantRef = em.getReference(Tenant, tenantId)\n const baseSlug = parsed.slug ? parsed.slug : slugify(parsed.name)\n const slug = baseSlug ? await resolveUniqueSlug(em, tenantId, baseSlug) : null\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let organization!: Organization\n await withAtomicFlush(em, [\n async () => {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n tenant: tenantRef,\n name: parsed.name,\n slug,\n logoUrl: parsed.logoUrl ?? null,\n isActive: parsed.isActive ?? true,\n parentId,\n },\n })\n setInternalTenantId(organization, tenantId)\n const recordId = String(organization.id)\n\n if (childIds.length) {\n await assignChildren(em, tenantId, recordId, childIds)\n }\n const childParentsAfter = await loadChildParentSnapshots(em, tenantId, childIds)\n setUndoMeta(organization, { childParentsBefore, childParentsAfter })\n\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: E.directory.organization,\n recordId,\n tenantId,\n organizationId: recordId,\n values: custom,\n })\n\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const recordId = String(organization.id)\n const identifiers = { id: recordId, organizationId: recordId, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: organization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return organization\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n return serializeOrganization(result, custom)\n },\n buildLog: async ({ result, ctx }) => {\n const { translate } = await resolveTranslations()\n const meta = getUndoMeta(result)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n const afterSnapshots = captureOrganizationSnapshots(result, meta.childParentsAfter ?? [], custom)\n return {\n actionLabel: translate('directory.audit.organizations.create', 'Create organization'),\n resourceKind: 'directory.organization',\n resourceId: String(result.id),\n tenantId: ctx.auth?.tenantId ?? resolveTenantIdFromEntity(result),\n snapshotAfter: afterSnapshots.view,\n payload: {\n undo: {\n after: afterSnapshots.undo,\n childrenBefore: meta.childParentsBefore ?? [],\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const after = payload?.after\n const childrenBefore = payload?.childrenBefore ?? []\n if (!after) return\n const tenantId = after.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await withAtomicFlush(em, [\n async () => {\n await restoreChildParents(em, tenantId, childrenBefore)\n if (after.custom && Object.keys(after.custom).length) {\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: after.id,\n tenantId,\n organizationId: after.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n await de.deleteOrmEntity({\n entity: Organization,\n where: { id: after.id, deletedAt: null } as FilterQuery<Organization>,\n soft: false,\n })\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<OrganizationUndoSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for organization create' })\n const tenantId = after.tenantId\n if (!tenantId) throw new CrudHttpError(400, { error: '[internal] redo snapshot missing tenant for organization create' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let organization!: Organization\n await withAtomicFlush(em, [\n async () => {\n const existing = await em.findOne(Organization, { id: after.id })\n if (existing) {\n existing.deletedAt = null\n existing.name = after.name\n if (after.slug !== undefined) existing.slug = after.slug ?? null\n if (after.logoUrl !== undefined) existing.logoUrl = after.logoUrl ?? null\n existing.isActive = after.isActive\n existing.parentId = after.parentId\n await em.flush()\n organization = existing\n } else {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n id: after.id,\n name: after.name,\n slug: after.slug ?? null,\n logoUrl: after.logoUrl ?? null,\n tenant: em.getReference(Tenant, tenantId),\n isActive: after.isActive,\n parentId: after.parentId,\n },\n })\n }\n setInternalTenantId(organization, tenantId)\n\n if (after.custom && Object.keys(after.custom).length) {\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: after.id,\n tenantId,\n organizationId: after.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n\n await assignChildren(em, tenantId, after.id, after.childParents.map((entry) => entry.childId))\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const identifiers = { id: after.id, organizationId: after.id, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: organization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return organization\n },\n}\n\nconst updateOrganizationCommand: CommandHandler<Record<string, unknown>, Organization> = {\n id: 'directory.organizations.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseWithCustomFields(organizationUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const current = await em.findOne(Organization, { id: parsed.id, deletedAt: null })\n if (!current) throw new CrudHttpError(404, { error: 'Not found' })\n const tenantId = resolveTenantIdFromEntity(current)\n const currentChildIds = Array.isArray(current.childIds) ? current.childIds : []\n const requestedChildIds = Array.isArray(parsed.childIds) ? parsed.childIds : []\n const combinedChildIds = new Set<string>([...currentChildIds.map(String), ...requestedChildIds.map(String)])\n const childParentsBefore = tenantId\n ? await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n : []\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(current.id),\n tenantId,\n organizationId: String(current.id),\n })\n return { before: captureOrganizationSnapshots(current, childParentsBefore, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, custom } = parseWithCustomFields(organizationUpdateSchema, rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id: parsed.id, deletedAt: null })\n if (!existing) throw new CrudHttpError(404, { error: 'Not found' })\n\n const tenantId = await enforceTenantSelection(ctx, parsed.tenantId ?? resolveTenantIdFromEntity(existing))\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = parsed.parentId ?? null\n if (parentId) {\n if (parentId === parsed.id) throw new CrudHttpError(400, { error: 'Organization cannot be its own parent' })\n if (Array.isArray(existing.descendantIds) && existing.descendantIds.includes(parentId)) {\n throw new CrudHttpError(400, { error: 'Cannot assign descendant as parent' })\n }\n await ensureParentExists(em, tenantId, parentId)\n }\n\n const normalizedChildIds = normalizeChildIds(parsed.childIds ?? [], [parsed.id, parentId ?? ''])\n if (normalizedChildIds.some((id) => id === parentId)) throw new CrudHttpError(400, { error: 'Child cannot equal parent' })\n if (Array.isArray(existing.ancestorIds) && normalizedChildIds.some((id) => existing.ancestorIds.includes(id))) {\n throw new CrudHttpError(400, { error: 'Cannot assign ancestor as child' })\n }\n\n if (normalizedChildIds.length) {\n await ensureChildrenValid(em, tenantId, normalizedChildIds)\n const childFilter = {\n tenant: tenantId,\n deletedAt: null,\n id: { $in: normalizedChildIds },\n } as unknown as FilterQuery<Organization>\n const children = await em.find(Organization, childFilter)\n for (const child of children) {\n if (Array.isArray(child.descendantIds) && child.descendantIds.includes(parsed.id)) {\n throw new CrudHttpError(400, { error: 'Cannot assign descendant cycle' })\n }\n }\n }\n\n const combinedChildIds = new Set<string>([\n ...normalizedChildIds.map(String),\n ...(Array.isArray(existing.childIds) ? existing.childIds.map(String) : []),\n ])\n const childParentsBefore = await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n\n let resolvedSlug: string | null | undefined\n if (parsed.slug !== undefined) {\n resolvedSlug = parsed.slug ? await resolveUniqueSlug(em, tenantId, parsed.slug, parsed.id) : parsed.slug\n }\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let resolvedOrganization!: Organization\n await withAtomicFlush(em, [\n async () => {\n const organization = await de.updateOrmEntity({\n entity: Organization,\n where: { id: parsed.id, deletedAt: null } as FilterQuery<Organization>,\n apply: (entity) => {\n if (parsed.name !== undefined) entity.name = parsed.name\n if (resolvedSlug !== undefined) entity.slug = resolvedSlug\n if (parsed.logoUrl !== undefined) entity.logoUrl = parsed.logoUrl ?? null\n if (parsed.isActive !== undefined) entity.isActive = parsed.isActive\n entity.parentId = parentId\n },\n })\n if (!organization) throw new CrudHttpError(404, { error: 'Not found' })\n setInternalTenantId(organization, tenantId)\n\n const recordId = String(organization.id)\n const desiredChildIds = new Set(normalizedChildIds.filter((id) => id !== recordId))\n await clearRemovedChildren(em, tenantId, recordId, desiredChildIds)\n await assignChildren(em, tenantId, recordId, desiredChildIds)\n const childParentsAfter = await loadChildParentSnapshots(em, tenantId, combinedChildIds)\n setUndoMeta(organization, { childParentsBefore, childParentsAfter })\n\n await setCustomFieldsIfAny({\n dataEngine: de,\n entityId: E.directory.organization,\n recordId,\n tenantId,\n organizationId: recordId,\n values: custom,\n })\n\n await rebuildHierarchyForTenant(em, tenantId)\n resolvedOrganization = organization\n },\n ], { transaction: true })\n\n const recordId = String(resolvedOrganization.id)\n const identifiers = { id: recordId, organizationId: recordId, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: resolvedOrganization,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return resolvedOrganization\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n return serializeOrganization(result, custom)\n },\n buildLog: async ({ snapshots, result, ctx }) => {\n const { translate } = await resolveTranslations()\n const meta = getUndoMeta(result)\n const beforeSnapshots = snapshots.before as OrganizationSnapshots | undefined\n const beforeRecord = beforeSnapshots?.view ?? null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const tenantId = resolveTenantIdFromEntity(result)\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(result.id),\n tenantId,\n organizationId: String(result.id),\n })\n const after = serializeOrganization(result, custom)\n const changes = buildChanges(beforeRecord, after as Record<string, unknown>, ['name', 'slug', 'logoUrl', 'isActive', 'parentId'])\n const customDiff = diffCustomFieldChanges(beforeRecord?.custom, custom)\n for (const [key, diff] of Object.entries(customDiff)) {\n changes[`cf_${key}`] = diff\n }\n return {\n actionLabel: translate('directory.audit.organizations.update', 'Update organization'),\n resourceKind: 'directory.organization',\n resourceId: String(result.id),\n changes,\n tenantId: ctx.auth?.tenantId ?? after.tenantId,\n payload: {\n undo: {\n before: beforeSnapshots?.undo ?? null,\n after: captureOrganizationSnapshots(result, meta.childParentsAfter ?? [], custom).undo,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const before = payload?.before\n const after = payload?.after\n if (!before) return\n const tenantId = before.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let updated: Organization | null = null\n await withAtomicFlush(em, [\n async () => {\n updated = await de.updateOrmEntity({\n entity: Organization,\n where: { id: before.id } as FilterQuery<Organization>,\n apply: (entity) => {\n entity.name = before.name\n if (before.slug !== undefined) entity.slug = before.slug\n if (before.logoUrl !== undefined) entity.logoUrl = before.logoUrl ?? null\n entity.isActive = before.isActive\n entity.parentId = before.parentId\n },\n })\n if (updated && tenantId) {\n setInternalTenantId(updated, tenantId)\n }\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n const resetValues = reset as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: before.id,\n tenantId,\n organizationId: before.id,\n values: resetValues,\n notify: false,\n })\n }\n const childSnapshots = before.childParents\n await restoreChildParents(em, tenantId, childSnapshots)\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: updated,\n identifiers: {\n id: before.id,\n tenantId,\n organizationId: before.id,\n },\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n },\n}\n\nconst deleteOrganizationCommand: CommandHandler<{ body: any; query: Record<string, string> }, Organization> = {\n id: 'directory.organizations.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Organization id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id, deletedAt: null })\n if (!existing) return {}\n const tenantId = resolveTenantIdFromEntity(existing)\n const childParentsBefore = tenantId\n ? await loadChildParentSnapshots(em, tenantId, Array.isArray(existing.childIds) ? existing.childIds : [])\n : []\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: E.directory.organization,\n recordId: String(existing.id),\n tenantId,\n organizationId: String(existing.id),\n })\n return { before: captureOrganizationSnapshots(existing, childParentsBefore, custom) }\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Organization id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const existing = await em.findOne(Organization, { id, deletedAt: null })\n if (!existing) throw new CrudHttpError(404, { error: 'Not found' })\n\n const tenantId = await enforceTenantSelection(ctx, resolveTenantIdFromEntity(existing))\n if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })\n\n const parentId = existing.parentId ?? null\n const childSnapshotsBefore = await loadChildParentSnapshots(\n em,\n tenantId,\n Array.isArray(existing.childIds) ? existing.childIds : [],\n )\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n\n let resolvedDeleted!: Organization\n await withAtomicFlush(em, [\n async () => {\n const deleted = await de.deleteOrmEntity({\n entity: Organization,\n where: { id, deletedAt: null } as FilterQuery<Organization>,\n soft: true,\n softDeleteField: 'deletedAt',\n })\n if (!deleted) throw new CrudHttpError(404, { error: 'Not found' })\n setInternalTenantId(deleted, tenantId)\n deleted.isActive = false\n deleted.parentId = null\n resolvedDeleted = deleted\n },\n async () => {\n const deleted = resolvedDeleted\n const childrenFilter: FilterQuery<Organization> = { tenant: tenantId, parentId: id, deletedAt: null }\n const children = await em.find(Organization, childrenFilter)\n const toPersist: Organization[] = []\n for (const child of children) {\n child.parentId = parentId\n toPersist.push(child)\n }\n toPersist.push(deleted)\n if (toPersist.length) em.persist(toPersist)\n setUndoMeta(deleted, { childParentsBefore: childSnapshotsBefore })\n },\n async () => {\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n\n const identifiers = { id, organizationId: id, tenantId }\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: resolvedDeleted,\n identifiers,\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n\n return resolvedDeleted\n },\n buildLog: async ({ snapshots, input, ctx }) => {\n const { translate } = await resolveTranslations()\n const beforeSnapshots = snapshots.before as OrganizationSnapshots | undefined\n const beforeSnapshot = beforeSnapshots?.view ?? null\n const beforeUndo = beforeSnapshots?.undo ?? null\n const id = String(input?.body?.id ?? input?.query?.id ?? '')\n const fallbackId = beforeSnapshot?.id ?? null\n const fallbackTenant = beforeSnapshot?.tenantId ?? null\n return {\n actionLabel: translate('directory.audit.organizations.delete', 'Delete organization'),\n resourceKind: 'directory.organization',\n resourceId: id || fallbackId || null,\n snapshotBefore: beforeSnapshot ?? null,\n tenantId: ctx.auth?.tenantId ?? fallbackTenant,\n payload: {\n undo: {\n before: beforeUndo,\n },\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<OrganizationUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const tenantId = before.tenantId\n if (!tenantId) return\n const em = (ctx.container.resolve('em') as EntityManager)\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n let organization: Organization | null = null\n await withAtomicFlush(em, [\n async () => {\n organization = await em.findOne(Organization, { id: before.id })\n if (organization) {\n organization.deletedAt = null\n organization.isActive = before.isActive\n organization.name = before.name\n if (before.slug !== undefined) organization.slug = before.slug\n organization.parentId = before.parentId\n await em.flush()\n if (tenantId) setInternalTenantId(organization, tenantId)\n } else {\n organization = await de.createOrmEntity({\n entity: Organization,\n data: {\n id: before.id,\n name: before.name,\n slug: before.slug ?? null,\n tenant: tenantId ? em.getReference(Tenant, tenantId) : undefined,\n isActive: before.isActive,\n parentId: before.parentId,\n },\n })\n if (tenantId) setInternalTenantId(organization, tenantId)\n }\n if (tenantId) {\n const customValues = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(customValues).length) {\n const resetValues = customValues as Parameters<DataEngine['setCustomFields']>[0]['values']\n await de.setCustomFields({\n entityId: E.directory.organization,\n recordId: before.id,\n tenantId,\n organizationId: before.id,\n values: resetValues,\n notify: false,\n })\n }\n }\n await restoreChildParents(em, tenantId, before.childParents)\n await rebuildHierarchyForTenant(em, tenantId)\n },\n ], { transaction: true })\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: organization,\n identifiers: {\n id: before.id,\n tenantId,\n organizationId: before.id,\n },\n events: organizationCrudEvents,\n indexer: organizationCrudIndexer,\n })\n },\n}\n\ntype OrganizationUndoPayload = {\n before?: OrganizationUndoSnapshot | null\n after?: OrganizationUndoSnapshot | null\n childrenBefore?: ChildParentSnapshot[] | null\n}\n\ntype OrganizationUndoMeta = {\n childParentsBefore?: ChildParentSnapshot[]\n childParentsAfter?: ChildParentSnapshot[]\n}\n\nconst UNDO_META_KEY: unique symbol = Symbol('directory.organization.undoMeta')\n\nfunction getUndoMeta(entity: Organization): OrganizationUndoMeta {\n return (Reflect.get(entity, UNDO_META_KEY) as OrganizationUndoMeta | undefined) ?? {}\n}\n\nfunction setUndoMeta(entity: Organization, meta: Partial<OrganizationUndoMeta>) {\n const current = getUndoMeta(entity)\n Reflect.set(entity, UNDO_META_KEY, { ...current, ...meta })\n}\n\nregisterCommand(createOrganizationCommand)\nregisterCommand(updateOrganizationCommand)\nregisterCommand(deleteOrganizationCommand)\n\nfunction setInternalTenantId(entity: Organization, tenantId: string) {\n Reflect.set(entity, '__tenantId', tenantId)\n}\n\nfunction tenantIdFromContext(ctx: CrudEmitContext<Organization>): string | null {\n return resolveTenantIdFromEntity(ctx.entity) ?? ctx.identifiers.tenantId ?? null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["recordId"]
7
7
  }
@@ -67,7 +67,7 @@ async function POST(req) {
67
67
  { lockMode: LockMode.PESSIMISTIC_WRITE },
68
68
  tenantScope
69
69
  );
70
- const quote2 = await findQuoteByToken(hashedToken) ?? await findQuoteByToken(token);
70
+ const quote2 = await findQuoteByToken(hashedToken);
71
71
  if (!quote2) {
72
72
  throw notFound(translate("sales.quotes.accept.notFound", "Quote not found."));
73
73
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/sales/api/quotes/accept/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { LockMode } from '@mikro-orm/core'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { getCachedRateLimiterService } from '@open-mercato/core/bootstrap'\nimport { readEndpointRateLimitConfig } from '@open-mercato/shared/lib/ratelimit/config'\nimport { checkRateLimit, getClientIp, rateLimitErrorSchema } from '@open-mercato/shared/lib/ratelimit/helpers'\nimport { validateSameOriginMutationRequest } from './originGuard'\nimport { hashAuthToken } from '../../../../auth/lib/tokenHash'\nimport { SalesOrder, SalesQuote } from '../../../data/entities'\nimport { quoteAcceptSchema } from '../../../data/validators'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { resolveStatusEntryIdByValue } from '../../../lib/statusHelpers'\nimport { QuoteAcceptedAdminEmail } from '../../../emails/QuoteAcceptedAdminEmail'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype ConvertToOrderResult = {\n result?: { orderId?: string } | null\n orderId?: string\n}\n\nexport const metadata = {\n POST: { requireAuth: false },\n}\n\nconst quoteAcceptRateLimitConfig = readEndpointRateLimitConfig('SALES_QUOTES_ACCEPT', {\n points: 10,\n duration: 60,\n blockDuration: 300,\n keyPrefix: 'sales_quote_accept',\n})\n\nexport async function POST(req: Request) {\n try {\n const { translate } = await resolveTranslations()\n const sameOriginViolation = validateSameOriginMutationRequest(req)\n if (sameOriginViolation) {\n return NextResponse.json(\n { error: translate('sales.quotes.accept.forbidden', 'Cross-site quote acceptance is not allowed.') },\n { status: 403 },\n )\n }\n\n const rateLimiterService = getCachedRateLimiterService()\n const clientIp = rateLimiterService ? getClientIp(req, rateLimiterService.trustProxyDepth) : null\n if (rateLimiterService && clientIp) {\n const rateLimitResponse = await checkRateLimit(\n rateLimiterService,\n quoteAcceptRateLimitConfig,\n clientIp,\n translate('api.errors.rateLimit', 'Too many requests. Please try again later.'),\n )\n if (rateLimitResponse) return rateLimitResponse\n }\n\n const { token } = quoteAcceptSchema.parse(await req.json().catch(() => ({})))\n const auth = await getAuthFromRequest(req)\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n\n const hashedToken = hashAuthToken(token)\n const tenantScope = auth?.tenantId ? { tenantId: auth.tenantId } : undefined\n\n const commandBus = container.resolve('commandBus') as CommandBus\n\n // Lock the quote, flip it to confirmed, and convert it to an order inside a\n // single transaction. The conversion command reuses this transaction (and its\n // PESSIMISTIC_WRITE lock) via ctx.transactionalEm, so the status flip and the\n // order creation are atomic: if conversion fails the whole transaction rolls\n // back, leaving the quote in its prior 'sent' state with no partial order and\n // no need for an out-of-band compensating write.\n const { quote, orderId } = await em.transactional(async (trx) => {\n const findQuoteByToken = (acceptanceToken: string) =>\n findOneWithDecryption(\n trx,\n SalesQuote,\n {\n acceptanceToken,\n ...(auth?.tenantId ? { tenantId: auth.tenantId } : {}),\n deletedAt: null,\n },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n tenantScope,\n )\n const quote = (await findQuoteByToken(hashedToken)) ?? (await findQuoteByToken(token))\n if (!quote) {\n throw notFound(translate('sales.quotes.accept.notFound', 'Quote not found.'))\n }\n\n const now = new Date()\n if (quote.validUntil && quote.validUntil.getTime() < now.getTime()) {\n throw new CrudHttpError(400, { error: translate('sales.quotes.accept.expired', 'This quote has expired.') })\n }\n\n if ((quote.status ?? null) !== 'sent') {\n throw new CrudHttpError(400, {\n error: translate('sales.quotes.accept.invalidStatus', 'This quote cannot be accepted in its current status.'),\n })\n }\n\n quote.status = 'confirmed'\n quote.statusEntryId = await resolveStatusEntryIdByValue(trx, {\n tenantId: quote.tenantId,\n organizationId: quote.organizationId,\n value: 'confirmed',\n })\n quote.updatedAt = now\n trx.persist(quote)\n await trx.flush()\n\n const ctx: CommandRuntimeContext = {\n container,\n auth: null,\n organizationScope: null,\n selectedOrganizationId: quote.organizationId,\n organizationIds: [quote.organizationId],\n request: req,\n transactionalEm: trx,\n }\n\n const result = (await commandBus.execute('sales.quotes.convert_to_order', { input: { quoteId: quote.id }, ctx })) as ConvertToOrderResult | null\n const orderId = result?.result?.orderId ?? result?.orderId ?? quote.id\n\n return { quote, orderId }\n })\n\n const order = await findOneWithDecryption(em, SalesOrder, { id: orderId, deletedAt: null }, {}, tenantScope)\n const orderNumber = order?.orderNumber ?? orderId\n\n // Admin notification should not block acceptance.\n const adminEmail = process.env.ADMIN_EMAIL || ''\n if (adminEmail) {\n try {\n const appUrl = process.env.APP_URL || ''\n const orderUrl = appUrl ? `${appUrl.replace(/\\/$/, '')}/backend/sales/orders/${orderId}` : `/backend/sales/orders/${orderId}`\n\n const copy = {\n preview: translate('sales.quotes.accept.adminEmail.preview', 'Quote {quoteNumber} accepted', { quoteNumber: quote.quoteNumber }),\n heading: translate('sales.quotes.accept.adminEmail.heading', 'Quote {quoteNumber} accepted', { quoteNumber: quote.quoteNumber }),\n body: translate('sales.quotes.accept.adminEmail.body', 'The customer accepted quote {quoteNumber}. An order has been created: {orderNumber}.', {\n quoteNumber: quote.quoteNumber,\n orderNumber,\n }),\n cta: translate('sales.quotes.accept.adminEmail.cta', 'View order'),\n footer: translate('sales.quotes.accept.adminEmail.footer', 'Open Mercato'),\n }\n\n await sendEmail({\n to: adminEmail,\n subject: translate('sales.quotes.accept.adminSubject', 'Quote {quoteNumber} accepted \u2192 Order {orderNumber}', {\n quoteNumber: quote.quoteNumber,\n orderNumber,\n }),\n react: QuoteAcceptedAdminEmail({ orderUrl, copy }),\n })\n } catch (err) {\n logger.error('sales.quotes.accept.adminEmail failed', { err })\n }\n }\n\n return NextResponse.json({ orderId, orderNumber })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.quotes.accept failed', { err })\n return NextResponse.json({ error: translate('sales.quotes.accept.failed', 'Failed to accept quote.') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Accept a quote (public)',\n methods: {\n POST: {\n summary: 'Accept quote and convert to order',\n requestBody: {\n contentType: 'application/json',\n schema: quoteAcceptSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Quote accepted and order created',\n schema: z.object({ orderId: z.string().uuid(), orderNumber: z.string() }),\n },\n { status: 400, description: 'Invalid or expired quote', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Cross-site request rejected', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'Quote not found', schema: z.object({ error: z.string() }) },\n { status: 429, description: 'Too many requests', schema: rateLimitErrorSchema },\n ],\n },\n },\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS;AAClB,SAAS,8BAA8B;AAEvC,SAAS,2BAA2B;AACpC,SAAS,eAAe,iBAAiB,gBAAgB;AAGzD,SAAS,gBAAgB;AACzB,SAAS,0BAA0B;AACnC,SAAS,6BAA6B;AACtC,SAAS,mCAAmC;AAC5C,SAAS,mCAAmC;AAC5C,SAAS,gBAAgB,aAAa,4BAA4B;AAClE,SAAS,yCAAyC;AAClD,SAAS,qBAAqB;AAC9B,SAAS,YAAY,kBAAkB;AACvC,SAAS,yBAAyB;AAClC,SAAS,iBAAiB;AAC1B,SAAS,mCAAmC;AAC5C,SAAS,+BAA+B;AACxC,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,OAAO;AAO5B,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM;AAC7B;AAEA,MAAM,6BAA6B,4BAA4B,uBAAuB;AAAA,EACpF,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,eAAe;AAAA,EACf,WAAW;AACb,CAAC;AAED,eAAsB,KAAK,KAAc;AACvC,MAAI;AACF,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,UAAM,sBAAsB,kCAAkC,GAAG;AACjE,QAAI,qBAAqB;AACvB,aAAO,aAAa;AAAA,QAClB,EAAE,OAAO,UAAU,iCAAiC,6CAA6C,EAAE;AAAA,QACnG,EAAE,QAAQ,IAAI;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,qBAAqB,4BAA4B;AACvD,UAAM,WAAW,qBAAqB,YAAY,KAAK,mBAAmB,eAAe,IAAI;AAC7F,QAAI,sBAAsB,UAAU;AAClC,YAAM,oBAAoB,MAAM;AAAA,QAC9B;AAAA,QACA;AAAA,QACA;AAAA,QACA,UAAU,wBAAwB,4CAA4C;AAAA,MAChF;AACA,UAAI,kBAAmB,QAAO;AAAA,IAChC;AAEA,UAAM,EAAE,MAAM,IAAI,kBAAkB,MAAM,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE,CAAC;AAC5E,UAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,UAAM,YAAY,MAAM,uBAAuB;AAC/C,UAAM,KAAM,UAAU,QAAQ,IAAI,EAAoB,KAAK;AAE3D,UAAM,cAAc,cAAc,KAAK;AACvC,UAAM,cAAc,MAAM,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI;AAEnE,UAAM,aAAa,UAAU,QAAQ,YAAY;AAQjD,UAAM,EAAE,OAAO,QAAQ,IAAI,MAAM,GAAG,cAAc,OAAO,QAAQ;AAC/D,YAAM,mBAAmB,CAAC,oBACxB;AAAA,QACE;AAAA,QACA;AAAA,QACA;AAAA,UACE;AAAA,UACA,GAAI,MAAM,WAAW,EAAE,UAAU,KAAK,SAAS,IAAI,CAAC;AAAA,UACpD,WAAW;AAAA,QACb;AAAA,QACA,EAAE,UAAU,SAAS,kBAAkB;AAAA,QACvC;AAAA,MACF;AACF,YAAMA,SAAS,MAAM,iBAAiB,WAAW,KAAO,MAAM,iBAAiB,KAAK;AACpF,UAAI,CAACA,QAAO;AACV,cAAM,SAAS,UAAU,gCAAgC,kBAAkB,CAAC;AAAA,MAC9E;AAEA,YAAM,MAAM,oBAAI,KAAK;AACrB,UAAIA,OAAM,cAAcA,OAAM,WAAW,QAAQ,IAAI,IAAI,QAAQ,GAAG;AAClE,cAAM,IAAI,cAAc,KAAK,EAAE,OAAO,UAAU,+BAA+B,yBAAyB,EAAE,CAAC;AAAA,MAC7G;AAEA,WAAKA,OAAM,UAAU,UAAU,QAAQ;AACrC,cAAM,IAAI,cAAc,KAAK;AAAA,UAC3B,OAAO,UAAU,qCAAqC,sDAAsD;AAAA,QAC9G,CAAC;AAAA,MACH;AAEA,MAAAA,OAAM,SAAS;AACf,MAAAA,OAAM,gBAAgB,MAAM,4BAA4B,KAAK;AAAA,QAC3D,UAAUA,OAAM;AAAA,QAChB,gBAAgBA,OAAM;AAAA,QACtB,OAAO;AAAA,MACT,CAAC;AACD,MAAAA,OAAM,YAAY;AAClB,UAAI,QAAQA,MAAK;AACjB,YAAM,IAAI,MAAM;AAEhB,YAAM,MAA6B;AAAA,QACjC;AAAA,QACA,MAAM;AAAA,QACN,mBAAmB;AAAA,QACnB,wBAAwBA,OAAM;AAAA,QAC9B,iBAAiB,CAACA,OAAM,cAAc;AAAA,QACtC,SAAS;AAAA,QACT,iBAAiB;AAAA,MACnB;AAEA,YAAM,SAAU,MAAM,WAAW,QAAQ,iCAAiC,EAAE,OAAO,EAAE,SAASA,OAAM,GAAG,GAAG,IAAI,CAAC;AAC/G,YAAMC,WAAU,QAAQ,QAAQ,WAAW,QAAQ,WAAWD,OAAM;AAEpE,aAAO,EAAE,OAAAA,QAAO,SAAAC,SAAQ;AAAA,IAC1B,CAAC;AAED,UAAM,QAAQ,MAAM,sBAAsB,IAAI,YAAY,EAAE,IAAI,SAAS,WAAW,KAAK,GAAG,CAAC,GAAG,WAAW;AAC3G,UAAM,cAAc,OAAO,eAAe;AAG1C,UAAM,aAAa,QAAQ,IAAI,eAAe;AAC9C,QAAI,YAAY;AACd,UAAI;AACF,cAAM,SAAS,QAAQ,IAAI,WAAW;AACtC,cAAM,WAAW,SAAS,GAAG,OAAO,QAAQ,OAAO,EAAE,CAAC,yBAAyB,OAAO,KAAK,yBAAyB,OAAO;AAE3H,cAAM,OAAO;AAAA,UACX,SAAS,UAAU,0CAA0C,gCAAgC,EAAE,aAAa,MAAM,YAAY,CAAC;AAAA,UAC/H,SAAS,UAAU,0CAA0C,gCAAgC,EAAE,aAAa,MAAM,YAAY,CAAC;AAAA,UAC/H,MAAM,UAAU,uCAAuC,wFAAwF;AAAA,YAC7I,aAAa,MAAM;AAAA,YACnB;AAAA,UACF,CAAC;AAAA,UACD,KAAK,UAAU,sCAAsC,YAAY;AAAA,UACjE,QAAQ,UAAU,yCAAyC,cAAc;AAAA,QAC3E;AAEA,cAAM,UAAU;AAAA,UACd,IAAI;AAAA,UACJ,SAAS,UAAU,oCAAoC,2DAAsD;AAAA,YAC3G,aAAa,MAAM;AAAA,YACnB;AAAA,UACF,CAAC;AAAA,UACD,OAAO,wBAAwB,EAAE,UAAU,KAAK,CAAC;AAAA,QACnD,CAAC;AAAA,MACH,SAAS,KAAK;AACZ,eAAO,MAAM,yCAAyC,EAAE,IAAI,CAAC;AAAA,MAC/D;AAAA,IACF;AAEA,WAAO,aAAa,KAAK,EAAE,SAAS,YAAY,CAAC;AAAA,EACnD,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,GAAG;AACxB,aAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC3D;AACA,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO,MAAM,8BAA8B,EAAE,IAAI,CAAC;AAClD,WAAO,aAAa,KAAK,EAAE,OAAO,UAAU,8BAA8B,yBAAyB,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EACzH;AACF;AAEO,MAAM,UAA2B;AAAA,EACtC,KAAK;AAAA,EACL,SAAS;AAAA,EACT,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT;AAAA,UACE,QAAQ;AAAA,UACR,aAAa;AAAA,UACb,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,GAAG,aAAa,EAAE,OAAO,EAAE,CAAC;AAAA,QAC1E;AAAA,QACA,EAAE,QAAQ,KAAK,aAAa,4BAA4B,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAAA,QAChG,EAAE,QAAQ,KAAK,aAAa,+BAA+B,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAAA,QACnG,EAAE,QAAQ,KAAK,aAAa,mBAAmB,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE;AAAA,QACvF,EAAE,QAAQ,KAAK,aAAa,qBAAqB,QAAQ,qBAAqB;AAAA,MAChF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { NextResponse } from 'next/server'\nimport { z } from 'zod'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError, isCrudHttpError, notFound } from '@open-mercato/shared/lib/crud/errors'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { LockMode } from '@mikro-orm/core'\nimport { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { getCachedRateLimiterService } from '@open-mercato/core/bootstrap'\nimport { readEndpointRateLimitConfig } from '@open-mercato/shared/lib/ratelimit/config'\nimport { checkRateLimit, getClientIp, rateLimitErrorSchema } from '@open-mercato/shared/lib/ratelimit/helpers'\nimport { validateSameOriginMutationRequest } from './originGuard'\nimport { hashAuthToken } from '../../../../auth/lib/tokenHash'\nimport { SalesOrder, SalesQuote } from '../../../data/entities'\nimport { quoteAcceptSchema } from '../../../data/validators'\nimport { sendEmail } from '@open-mercato/shared/lib/email/send'\nimport { resolveStatusEntryIdByValue } from '../../../lib/statusHelpers'\nimport { QuoteAcceptedAdminEmail } from '../../../emails/QuoteAcceptedAdminEmail'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype ConvertToOrderResult = {\n result?: { orderId?: string } | null\n orderId?: string\n}\n\nexport const metadata = {\n POST: { requireAuth: false },\n}\n\nconst quoteAcceptRateLimitConfig = readEndpointRateLimitConfig('SALES_QUOTES_ACCEPT', {\n points: 10,\n duration: 60,\n blockDuration: 300,\n keyPrefix: 'sales_quote_accept',\n})\n\nexport async function POST(req: Request) {\n try {\n const { translate } = await resolveTranslations()\n const sameOriginViolation = validateSameOriginMutationRequest(req)\n if (sameOriginViolation) {\n return NextResponse.json(\n { error: translate('sales.quotes.accept.forbidden', 'Cross-site quote acceptance is not allowed.') },\n { status: 403 },\n )\n }\n\n const rateLimiterService = getCachedRateLimiterService()\n const clientIp = rateLimiterService ? getClientIp(req, rateLimiterService.trustProxyDepth) : null\n if (rateLimiterService && clientIp) {\n const rateLimitResponse = await checkRateLimit(\n rateLimiterService,\n quoteAcceptRateLimitConfig,\n clientIp,\n translate('api.errors.rateLimit', 'Too many requests. Please try again later.'),\n )\n if (rateLimitResponse) return rateLimitResponse\n }\n\n const { token } = quoteAcceptSchema.parse(await req.json().catch(() => ({})))\n const auth = await getAuthFromRequest(req)\n const container = await createRequestContainer()\n const em = (container.resolve('em') as EntityManager).fork()\n\n const hashedToken = hashAuthToken(token)\n const tenantScope = auth?.tenantId ? { tenantId: auth.tenantId } : undefined\n\n const commandBus = container.resolve('commandBus') as CommandBus\n\n // Lock the quote, flip it to confirmed, and convert it to an order inside a\n // single transaction. The conversion command reuses this transaction (and its\n // PESSIMISTIC_WRITE lock) via ctx.transactionalEm, so the status flip and the\n // order creation are atomic: if conversion fails the whole transaction rolls\n // back, leaving the quote in its prior 'sent' state with no partial order and\n // no need for an out-of-band compensating write.\n const { quote, orderId } = await em.transactional(async (trx) => {\n const findQuoteByToken = (acceptanceToken: string) =>\n findOneWithDecryption(\n trx,\n SalesQuote,\n {\n acceptanceToken,\n ...(auth?.tenantId ? { tenantId: auth.tenantId } : {}),\n deletedAt: null,\n },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n tenantScope,\n )\n const quote = await findQuoteByToken(hashedToken)\n if (!quote) {\n throw notFound(translate('sales.quotes.accept.notFound', 'Quote not found.'))\n }\n\n const now = new Date()\n if (quote.validUntil && quote.validUntil.getTime() < now.getTime()) {\n throw new CrudHttpError(400, { error: translate('sales.quotes.accept.expired', 'This quote has expired.') })\n }\n\n if ((quote.status ?? null) !== 'sent') {\n throw new CrudHttpError(400, {\n error: translate('sales.quotes.accept.invalidStatus', 'This quote cannot be accepted in its current status.'),\n })\n }\n\n quote.status = 'confirmed'\n quote.statusEntryId = await resolveStatusEntryIdByValue(trx, {\n tenantId: quote.tenantId,\n organizationId: quote.organizationId,\n value: 'confirmed',\n })\n quote.updatedAt = now\n trx.persist(quote)\n await trx.flush()\n\n const ctx: CommandRuntimeContext = {\n container,\n auth: null,\n organizationScope: null,\n selectedOrganizationId: quote.organizationId,\n organizationIds: [quote.organizationId],\n request: req,\n transactionalEm: trx,\n }\n\n const result = (await commandBus.execute('sales.quotes.convert_to_order', { input: { quoteId: quote.id }, ctx })) as ConvertToOrderResult | null\n const orderId = result?.result?.orderId ?? result?.orderId ?? quote.id\n\n return { quote, orderId }\n })\n\n const order = await findOneWithDecryption(em, SalesOrder, { id: orderId, deletedAt: null }, {}, tenantScope)\n const orderNumber = order?.orderNumber ?? orderId\n\n // Admin notification should not block acceptance.\n const adminEmail = process.env.ADMIN_EMAIL || ''\n if (adminEmail) {\n try {\n const appUrl = process.env.APP_URL || ''\n const orderUrl = appUrl ? `${appUrl.replace(/\\/$/, '')}/backend/sales/orders/${orderId}` : `/backend/sales/orders/${orderId}`\n\n const copy = {\n preview: translate('sales.quotes.accept.adminEmail.preview', 'Quote {quoteNumber} accepted', { quoteNumber: quote.quoteNumber }),\n heading: translate('sales.quotes.accept.adminEmail.heading', 'Quote {quoteNumber} accepted', { quoteNumber: quote.quoteNumber }),\n body: translate('sales.quotes.accept.adminEmail.body', 'The customer accepted quote {quoteNumber}. An order has been created: {orderNumber}.', {\n quoteNumber: quote.quoteNumber,\n orderNumber,\n }),\n cta: translate('sales.quotes.accept.adminEmail.cta', 'View order'),\n footer: translate('sales.quotes.accept.adminEmail.footer', 'Open Mercato'),\n }\n\n await sendEmail({\n to: adminEmail,\n subject: translate('sales.quotes.accept.adminSubject', 'Quote {quoteNumber} accepted \u2192 Order {orderNumber}', {\n quoteNumber: quote.quoteNumber,\n orderNumber,\n }),\n react: QuoteAcceptedAdminEmail({ orderUrl, copy }),\n })\n } catch (err) {\n logger.error('sales.quotes.accept.adminEmail failed', { err })\n }\n }\n\n return NextResponse.json({ orderId, orderNumber })\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status })\n }\n const { translate } = await resolveTranslations()\n logger.error('sales.quotes.accept failed', { err })\n return NextResponse.json({ error: translate('sales.quotes.accept.failed', 'Failed to accept quote.') }, { status: 400 })\n }\n}\n\nexport const openApi: OpenApiRouteDoc = {\n tag: 'Sales',\n summary: 'Accept a quote (public)',\n methods: {\n POST: {\n summary: 'Accept quote and convert to order',\n requestBody: {\n contentType: 'application/json',\n schema: quoteAcceptSchema,\n },\n responses: [\n {\n status: 200,\n description: 'Quote accepted and order created',\n schema: z.object({ orderId: z.string().uuid(), orderNumber: z.string() }),\n },\n { status: 400, description: 'Invalid or expired quote', schema: z.object({ error: z.string() }) },\n { status: 403, description: 'Cross-site request rejected', schema: z.object({ error: z.string() }) },\n { status: 404, description: 'Quote not found', schema: z.object({ error: z.string() }) },\n { status: 429, description: 'Too many requests', schema: rateLimitErrorSchema },\n ],\n },\n },\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["quote", "orderId"]
7
7
  }
@@ -29,9 +29,6 @@ async function GET(req, ctx) {
29
29
  const quote = await findOneWithDecryption(em, SalesQuote, {
30
30
  acceptanceToken: hashedToken,
31
31
  deletedAt: null
32
- }) ?? await findOneWithDecryption(em, SalesQuote, {
33
- acceptanceToken: token,
34
- deletedAt: null
35
32
  });
36
33
  const { translate } = await resolveTranslations();
37
34
  if (!quote) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/sales/api/quotes/public/%5Btoken%5D/route.ts"],
4
- "sourcesContent": ["import { NextResponse } from \"next/server\";\nimport { z } from \"zod\";\nimport { createRequestContainer } from \"@open-mercato/shared/lib/di/container\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport { isCrudHttpError, notFound } from \"@open-mercato/shared/lib/crud/errors\";\nimport type { OpenApiRouteDoc } from \"@open-mercato/shared/lib/openapi\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { findOneWithDecryption, findWithDecryption } from \"@open-mercato/shared/lib/encryption/find\";\nimport { hashAuthToken } from \"../../../../../auth/lib/tokenHash\";\nimport {\n SalesQuote,\n SalesQuoteLine,\n SalesQuoteAdjustment,\n} from \"../../../../data/entities\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport { getAuthFromRequest } from \"@open-mercato/shared/lib/auth/server\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nconst paramsSchema = z.object({\n token: z.string().uuid(),\n});\n\nexport const metadata = {\n GET: { requireAuth: false },\n};\n\nexport async function GET(req: Request, ctx: { params: { token: string } }) {\n try {\n const { token } = paramsSchema.parse(ctx.params ?? {});\n const container = await createRequestContainer();\n const em = container.resolve(\"em\") as EntityManager;\n const hashedToken = hashAuthToken(token);\n const quote =\n (await findOneWithDecryption(em, SalesQuote, {\n acceptanceToken: hashedToken,\n deletedAt: null,\n })) ??\n (await findOneWithDecryption(em, SalesQuote, {\n acceptanceToken: token,\n deletedAt: null,\n }));\n const { translate } = await resolveTranslations();\n if (!quote) {\n throw notFound(translate(\"sales.quotes.public.notFound\", \"Quote not found.\"));\n }\n\n const auth = await getAuthFromRequest(req);\n if (auth?.tenantId && quote.tenantId !== auth.tenantId) {\n throw notFound(translate(\"sales.quotes.public.notFound\", \"Quote not found.\"));\n }\n\n const now = new Date();\n const isExpired =\n !!quote.validUntil && quote.validUntil.getTime() < now.getTime();\n\n const [lines, adjustments] = await Promise.all([\n findWithDecryption(\n em,\n SalesQuoteLine,\n { quote: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId, deletedAt: null },\n { orderBy: { lineNumber: \"asc\" } },\n ),\n findWithDecryption(\n em,\n SalesQuoteAdjustment,\n { quote: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId },\n { orderBy: { position: \"asc\" } },\n ),\n ]);\n\n return NextResponse.json({\n quote: {\n quoteNumber: quote.quoteNumber,\n currencyCode: quote.currencyCode,\n validFrom: quote.validFrom?.toISOString() ?? null,\n validUntil: quote.validUntil?.toISOString() ?? null,\n status: quote.status ?? null,\n subtotalNetAmount: quote.subtotalNetAmount,\n subtotalGrossAmount: quote.subtotalGrossAmount,\n discountTotalAmount: quote.discountTotalAmount,\n taxTotalAmount: quote.taxTotalAmount,\n grandTotalNetAmount: quote.grandTotalNetAmount,\n grandTotalGrossAmount: quote.grandTotalGrossAmount,\n },\n lines: lines.map((line) => ({\n lineNumber: line.lineNumber ?? null,\n kind: line.kind,\n name: line.name ?? null,\n description: line.description ?? null,\n quantity: line.quantity,\n quantityUnit: canonicalizeUnitCode(line.quantityUnit) ?? null,\n normalizedQuantity: line.normalizedQuantity ?? line.quantity,\n normalizedUnit:\n canonicalizeUnitCode(line.normalizedUnit ?? line.quantityUnit) ??\n null,\n uomSnapshot: line.uomSnapshot\n ? {\n baseUnitCode: line.uomSnapshot.baseUnitCode ?? null,\n enteredUnitCode: line.uomSnapshot.enteredUnitCode ?? null,\n }\n : null,\n currencyCode: line.currencyCode,\n unitPriceNet: line.unitPriceNet,\n unitPriceGross: line.unitPriceGross,\n discountAmount: line.discountAmount,\n discountPercent: line.discountPercent,\n taxRate: line.taxRate,\n taxAmount: line.taxAmount,\n totalNetAmount: line.totalNetAmount,\n totalGrossAmount: line.totalGrossAmount,\n unitPriceReference: (() => {\n if (!line.uomSnapshot) return null;\n const ref = line.uomSnapshot.unitPriceReference;\n if (!ref) return null;\n return {\n enabled: ref.enabled ?? null,\n referenceUnitCode: ref.referenceUnitCode ?? null,\n baseQuantity: ref.baseQuantity ?? null,\n grossPerReference: ref.grossPerReference ?? null,\n netPerReference: ref.netPerReference ?? null,\n };\n })(),\n })),\n adjustments: adjustments.map((adj) => ({\n scope: adj.scope,\n kind: adj.kind,\n label: adj.label ?? adj.code ?? null,\n rate: adj.rate,\n amountNet: adj.amountNet,\n amountGross: adj.amountGross,\n currencyCode: adj.currencyCode ?? null,\n position: adj.position ?? null,\n quoteLineId: adj.quoteLine?.id ?? null,\n })),\n isExpired,\n });\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status });\n }\n const { translate } = await resolveTranslations();\n logger.error('sales.quotes.public failed', { err });\n return NextResponse.json(\n {\n error: translate(\"sales.quotes.public.failed\", \"Failed to load quote.\"),\n },\n { status: 400 },\n );\n }\n}\n\nconst publicQuoteResponseSchema = z.object({\n quote: z.object({\n quoteNumber: z.string(),\n currencyCode: z.string(),\n validFrom: z.string().nullable(),\n validUntil: z.string().nullable(),\n status: z.string().nullable(),\n subtotalNetAmount: z.string(),\n subtotalGrossAmount: z.string(),\n discountTotalAmount: z.string(),\n taxTotalAmount: z.string(),\n grandTotalNetAmount: z.string(),\n grandTotalGrossAmount: z.string(),\n }),\n lines: z.array(\n z.object({\n lineNumber: z.number().nullable(),\n kind: z.string(),\n name: z.string().nullable(),\n description: z.string().nullable(),\n quantity: z.string(),\n quantityUnit: z.string().nullable(),\n normalizedQuantity: z.string(),\n normalizedUnit: z.string().nullable(),\n uomSnapshot: z\n .object({\n baseUnitCode: z.string().nullable(),\n enteredUnitCode: z.string().nullable(),\n })\n .nullable()\n .optional(),\n currencyCode: z.string(),\n unitPriceNet: z.string(),\n unitPriceGross: z.string(),\n discountAmount: z.string(),\n discountPercent: z.string(),\n taxRate: z.string(),\n taxAmount: z.string(),\n totalNetAmount: z.string(),\n totalGrossAmount: z.string(),\n unitPriceReference: z\n .object({\n enabled: z.boolean().nullable().optional(),\n referenceUnitCode: z.string().nullable().optional(),\n baseQuantity: z.string().nullable().optional(),\n grossPerReference: z.string().nullable().optional(),\n netPerReference: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n }),\n ),\n adjustments: z.array(\n z.object({\n scope: z.string().nullable(),\n kind: z.string().nullable(),\n label: z.string().nullable(),\n rate: z.string().nullable(),\n amountNet: z.string().nullable(),\n amountGross: z.string().nullable(),\n currencyCode: z.string().nullable(),\n position: z.number().nullable(),\n quoteLineId: z.string().uuid().nullable(),\n }),\n ),\n isExpired: z.boolean(),\n});\n\nexport const openApi: OpenApiRouteDoc = {\n tag: \"Sales\",\n summary: \"View a quote (public)\",\n pathParams: z.object({ token: z.string().uuid() }),\n methods: {\n GET: {\n summary: \"Get quote details by acceptance token\",\n responses: [\n {\n status: 200,\n description: \"Quote details\",\n schema: publicQuoteResponseSchema,\n },\n {\n status: 404,\n description: \"Quote not found\",\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n};\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { NextResponse } from \"next/server\";\nimport { z } from \"zod\";\nimport { createRequestContainer } from \"@open-mercato/shared/lib/di/container\";\nimport { resolveTranslations } from \"@open-mercato/shared/lib/i18n/server\";\nimport { isCrudHttpError, notFound } from \"@open-mercato/shared/lib/crud/errors\";\nimport type { OpenApiRouteDoc } from \"@open-mercato/shared/lib/openapi\";\nimport type { EntityManager } from \"@mikro-orm/postgresql\";\nimport { findOneWithDecryption, findWithDecryption } from \"@open-mercato/shared/lib/encryption/find\";\nimport { hashAuthToken } from \"../../../../../auth/lib/tokenHash\";\nimport {\n SalesQuote,\n SalesQuoteLine,\n SalesQuoteAdjustment,\n} from \"../../../../data/entities\";\nimport { canonicalizeUnitCode } from \"@open-mercato/shared/lib/units/unitCodes\";\nimport { getAuthFromRequest } from \"@open-mercato/shared/lib/auth/server\";\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\nconst paramsSchema = z.object({\n token: z.string().uuid(),\n});\n\nexport const metadata = {\n GET: { requireAuth: false },\n};\n\nexport async function GET(req: Request, ctx: { params: { token: string } }) {\n try {\n const { token } = paramsSchema.parse(ctx.params ?? {});\n const container = await createRequestContainer();\n const em = container.resolve(\"em\") as EntityManager;\n const hashedToken = hashAuthToken(token);\n const quote = await findOneWithDecryption(em, SalesQuote, {\n acceptanceToken: hashedToken,\n deletedAt: null,\n });\n const { translate } = await resolveTranslations();\n if (!quote) {\n throw notFound(translate(\"sales.quotes.public.notFound\", \"Quote not found.\"));\n }\n\n const auth = await getAuthFromRequest(req);\n if (auth?.tenantId && quote.tenantId !== auth.tenantId) {\n throw notFound(translate(\"sales.quotes.public.notFound\", \"Quote not found.\"));\n }\n\n const now = new Date();\n const isExpired =\n !!quote.validUntil && quote.validUntil.getTime() < now.getTime();\n\n const [lines, adjustments] = await Promise.all([\n findWithDecryption(\n em,\n SalesQuoteLine,\n { quote: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId, deletedAt: null },\n { orderBy: { lineNumber: \"asc\" } },\n ),\n findWithDecryption(\n em,\n SalesQuoteAdjustment,\n { quote: quote.id, organizationId: quote.organizationId, tenantId: quote.tenantId },\n { orderBy: { position: \"asc\" } },\n ),\n ]);\n\n return NextResponse.json({\n quote: {\n quoteNumber: quote.quoteNumber,\n currencyCode: quote.currencyCode,\n validFrom: quote.validFrom?.toISOString() ?? null,\n validUntil: quote.validUntil?.toISOString() ?? null,\n status: quote.status ?? null,\n subtotalNetAmount: quote.subtotalNetAmount,\n subtotalGrossAmount: quote.subtotalGrossAmount,\n discountTotalAmount: quote.discountTotalAmount,\n taxTotalAmount: quote.taxTotalAmount,\n grandTotalNetAmount: quote.grandTotalNetAmount,\n grandTotalGrossAmount: quote.grandTotalGrossAmount,\n },\n lines: lines.map((line) => ({\n lineNumber: line.lineNumber ?? null,\n kind: line.kind,\n name: line.name ?? null,\n description: line.description ?? null,\n quantity: line.quantity,\n quantityUnit: canonicalizeUnitCode(line.quantityUnit) ?? null,\n normalizedQuantity: line.normalizedQuantity ?? line.quantity,\n normalizedUnit:\n canonicalizeUnitCode(line.normalizedUnit ?? line.quantityUnit) ??\n null,\n uomSnapshot: line.uomSnapshot\n ? {\n baseUnitCode: line.uomSnapshot.baseUnitCode ?? null,\n enteredUnitCode: line.uomSnapshot.enteredUnitCode ?? null,\n }\n : null,\n currencyCode: line.currencyCode,\n unitPriceNet: line.unitPriceNet,\n unitPriceGross: line.unitPriceGross,\n discountAmount: line.discountAmount,\n discountPercent: line.discountPercent,\n taxRate: line.taxRate,\n taxAmount: line.taxAmount,\n totalNetAmount: line.totalNetAmount,\n totalGrossAmount: line.totalGrossAmount,\n unitPriceReference: (() => {\n if (!line.uomSnapshot) return null;\n const ref = line.uomSnapshot.unitPriceReference;\n if (!ref) return null;\n return {\n enabled: ref.enabled ?? null,\n referenceUnitCode: ref.referenceUnitCode ?? null,\n baseQuantity: ref.baseQuantity ?? null,\n grossPerReference: ref.grossPerReference ?? null,\n netPerReference: ref.netPerReference ?? null,\n };\n })(),\n })),\n adjustments: adjustments.map((adj) => ({\n scope: adj.scope,\n kind: adj.kind,\n label: adj.label ?? adj.code ?? null,\n rate: adj.rate,\n amountNet: adj.amountNet,\n amountGross: adj.amountGross,\n currencyCode: adj.currencyCode ?? null,\n position: adj.position ?? null,\n quoteLineId: adj.quoteLine?.id ?? null,\n })),\n isExpired,\n });\n } catch (err) {\n if (isCrudHttpError(err)) {\n return NextResponse.json(err.body, { status: err.status });\n }\n const { translate } = await resolveTranslations();\n logger.error('sales.quotes.public failed', { err });\n return NextResponse.json(\n {\n error: translate(\"sales.quotes.public.failed\", \"Failed to load quote.\"),\n },\n { status: 400 },\n );\n }\n}\n\nconst publicQuoteResponseSchema = z.object({\n quote: z.object({\n quoteNumber: z.string(),\n currencyCode: z.string(),\n validFrom: z.string().nullable(),\n validUntil: z.string().nullable(),\n status: z.string().nullable(),\n subtotalNetAmount: z.string(),\n subtotalGrossAmount: z.string(),\n discountTotalAmount: z.string(),\n taxTotalAmount: z.string(),\n grandTotalNetAmount: z.string(),\n grandTotalGrossAmount: z.string(),\n }),\n lines: z.array(\n z.object({\n lineNumber: z.number().nullable(),\n kind: z.string(),\n name: z.string().nullable(),\n description: z.string().nullable(),\n quantity: z.string(),\n quantityUnit: z.string().nullable(),\n normalizedQuantity: z.string(),\n normalizedUnit: z.string().nullable(),\n uomSnapshot: z\n .object({\n baseUnitCode: z.string().nullable(),\n enteredUnitCode: z.string().nullable(),\n })\n .nullable()\n .optional(),\n currencyCode: z.string(),\n unitPriceNet: z.string(),\n unitPriceGross: z.string(),\n discountAmount: z.string(),\n discountPercent: z.string(),\n taxRate: z.string(),\n taxAmount: z.string(),\n totalNetAmount: z.string(),\n totalGrossAmount: z.string(),\n unitPriceReference: z\n .object({\n enabled: z.boolean().nullable().optional(),\n referenceUnitCode: z.string().nullable().optional(),\n baseQuantity: z.string().nullable().optional(),\n grossPerReference: z.string().nullable().optional(),\n netPerReference: z.string().nullable().optional(),\n })\n .nullable()\n .optional(),\n }),\n ),\n adjustments: z.array(\n z.object({\n scope: z.string().nullable(),\n kind: z.string().nullable(),\n label: z.string().nullable(),\n rate: z.string().nullable(),\n amountNet: z.string().nullable(),\n amountGross: z.string().nullable(),\n currencyCode: z.string().nullable(),\n position: z.number().nullable(),\n quoteLineId: z.string().uuid().nullable(),\n }),\n ),\n isExpired: z.boolean(),\n});\n\nexport const openApi: OpenApiRouteDoc = {\n tag: \"Sales\",\n summary: \"View a quote (public)\",\n pathParams: z.object({ token: z.string().uuid() }),\n methods: {\n GET: {\n summary: \"Get quote details by acceptance token\",\n responses: [\n {\n status: 200,\n description: \"Quote details\",\n schema: publicQuoteResponseSchema,\n },\n {\n status: 404,\n description: \"Quote not found\",\n schema: z.object({ error: z.string() }),\n },\n ],\n },\n },\n};\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -526,6 +526,7 @@ function SalesDocumentsTable({ kind }) {
526
526
  /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(
527
527
  DataTable,
528
528
  {
529
+ stickyFirstColumn: true,
529
530
  stickyActionsColumn: true,
530
531
  title: /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
531
532
  /* @__PURE__ */ jsx("span", { children: title }),
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/components/documents/SalesDocumentsTable.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { SALES_DOCUMENT_NUMBER_COLUMN_META } from './salesDocumentsColumns'\nimport { useSalesChannelsEnabled } from '../useSalesChannelsEnabled'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype SalesDocumentKind = 'order' | 'quote'\n\ntype FilterOption = { value: string; label: string; description?: string | null }\n\ntype CustomerSnapshot = {\n customer?: {\n displayName?: string | null\n primaryEmail?: string | null\n } | null\n contact?: {\n firstName?: string | null\n lastName?: string | null\n preferredName?: string | null\n } | null\n}\n\ntype ApiDocument = {\n id: string\n orderNumber?: string | null\n quoteNumber?: string | null\n status?: string | null\n customerEntityId?: string | null\n customerSnapshot?: Record<string, unknown> | null\n channelId?: string | null\n lineItemCount?: number | null\n grandTotalNetAmount?: number | null\n grandTotalGrossAmount?: number | null\n currencyCode?: string | null\n placedAt?: string | null\n validUntil?: string | null\n validFrom?: string | null\n createdAt?: string | null\n updatedAt?: string | null\n}\n\ntype DocumentsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype SalesDocumentRow = {\n id: string\n number: string\n status?: string | null\n customerName?: string | null\n customerEmail?: string | null\n channelId?: string | null\n lineItemCount?: number | null\n totalNet?: number | null\n totalGross?: number | null\n currency?: string | null\n date?: string | null\n updatedAt?: string | null\n}\n\nconst PAGE_SIZE = 20\n\nfunction resolveCustomerName(snapshot: CustomerSnapshot | null | undefined, fallback?: string | null) {\n if (!snapshot) return fallback ?? null\n const base = snapshot.customer?.displayName ?? null\n if (base) return base\n const contact = snapshot.contact\n if (contact) {\n const parts = [contact.preferredName, contact.firstName, contact.lastName].filter(\n (part) => part && part.trim().length\n ) as string[]\n if (parts.length) return parts.join(' ')\n }\n return fallback ?? null\n}\n\nfunction resolveCustomerEmail(snapshot: CustomerSnapshot | null | undefined) {\n if (!snapshot) return null\n if (snapshot.customer?.primaryEmail) return snapshot.customer.primaryEmail\n return null\n}\n\nfunction toNumber(value: unknown): number | null {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction formatCurrency(amount: number | null | undefined, currency: string | null | undefined, fallback = '\u2014') {\n if (amount == null || Number.isNaN(amount)) return fallback\n try {\n if (currency && currency.trim().length) {\n const formatter = new Intl.NumberFormat(undefined, { style: 'currency', currency })\n return formatter.format(amount)\n }\n return new Intl.NumberFormat(undefined, { style: 'decimal', maximumFractionDigits: 2 }).format(amount)\n } catch {\n return String(amount)\n }\n}\n\nfunction mergeOptions(existing: FilterOption[], next: FilterOption[]): FilterOption[] {\n const map = new Map<string, FilterOption>()\n existing.forEach((opt) => map.set(opt.value, opt))\n next.forEach((opt) => map.set(opt.value, opt))\n return Array.from(map.values()).sort((a, b) => a.label.localeCompare(b.label))\n}\n\nfunction normalizeNumberInput(value: unknown): number | null {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nexport function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {\n const t = useT()\n const { enabled: channelsEnabled } = useSalesChannelsEnabled()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<SalesDocumentRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'createdAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setLoading] = React.useState(false)\n const [cacheStatus, setCacheStatus] = React.useState<'hit' | 'miss' | null>(null)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [channelOptions, setChannelOptions] = React.useState<FilterOption[]>([])\n const [tagOptions, setTagOptions] = React.useState<FilterOption[]>([])\n const [customerOptions, setCustomerOptions] = React.useState<FilterOption[]>([])\n const [statusMap, setStatusMap] = React.useState<DictionaryMap>({})\n\n const resource = kind === 'order' ? 'orders' : 'quotes'\n const entityId = kind === 'order' ? E.sales.sales_order : E.sales.sales_quote\n const title = kind === 'order'\n ? t('sales.documents.list.ordersTitle', 'Sales orders')\n : t('sales.documents.list.quotesTitle', 'Sales quotes')\n const subtitle = t(\n 'sales.documents.list.subtitle',\n 'Review documents with customer context, totals, and channels.'\n )\n\n const fetchChannelOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '50' })\n if (query && query.trim()) params.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/sales/channels?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const name = typeof item?.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((opt): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n }, [])\n\n const fetchTagOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '50' })\n if (query && query.trim()) params.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/sales/tags?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const label = typeof item?.label === 'string' ? item.label : null\n if (!id || !label) return null\n const description = typeof item?.description === 'string' ? item.description : null\n return { value: id, label, description }\n })\n .filter((opt): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n }, [])\n\n const fetchCustomerOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '20' })\n if (query && query.trim().length) params.set('search', query.trim())\n try {\n const [people, companies] = await Promise.all([\n apiCall<{ items?: unknown[] }>(`/api/customers/people?${params.toString()}`),\n apiCall<{ items?: unknown[] }>(`/api/customers/companies?${params.toString()}`),\n ])\n const peopleItems = Array.isArray(people.result?.items) ? people.result?.items ?? [] : []\n const companyItems = Array.isArray(companies.result?.items) ? companies.result?.items ?? [] : []\n const parseOption = (item: any, kind: 'person' | 'company'): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n if (!id) return null\n const name =\n typeof item?.display_name === 'string' && item.display_name.trim().length\n ? item.display_name\n : typeof item?.name === 'string' && item.name.trim().length\n ? item.name\n : id\n const email =\n typeof item?.primary_email === 'string' && item.primary_email.trim().length\n ? item.primary_email.trim()\n : null\n const label = email ? `${name} (${email})` : name\n return { value: id, label }\n }\n const options = [...peopleItems.map((i) => parseOption(i, 'person')), ...companyItems.map((i) => parseOption(i, 'company'))]\n .filter((opt): opt is FilterOption => !!opt)\n return options\n } catch {\n return []\n }\n }, [])\n\n const loadStatusMap = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false })\n setStatusMap(createDictionaryMap(entries))\n } catch (err) {\n logger.error('sales.documents.statuses.load', { err })\n setStatusMap({})\n }\n }, [])\n\n const loadChannelOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchChannelOptions(query)\n if (opts.length) setChannelOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchChannelOptions]\n )\n\n const loadTagOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchTagOptions(query)\n if (opts.length) setTagOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchTagOptions]\n )\n\n const loadCustomerOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchCustomerOptions(query)\n if (opts.length) setCustomerOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchCustomerOptions]\n )\n\n React.useEffect(() => {\n if (channelsEnabled) loadChannelOptions().catch(() => {})\n loadTagOptions().catch(() => {})\n loadCustomerOptions().catch(() => {})\n loadStatusMap().catch(() => setStatusMap({}))\n }, [channelsEnabled, loadChannelOptions, loadCustomerOptions, loadStatusMap, loadTagOptions, scopeVersion])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n ...(channelsEnabled ? [{\n id: 'channelId',\n label: t('sales.documents.list.filters.channel', 'Channel'),\n type: 'select',\n options: channelOptions,\n loadOptions: loadChannelOptions,\n } satisfies FilterDef] : []),\n {\n id: 'date',\n label: t('sales.documents.list.filters.date', 'Date'),\n type: 'dateRange',\n },\n {\n id: 'lineItemCountMin',\n label: t('sales.documents.list.filters.itemsMin', 'Min items'),\n type: 'text',\n },\n {\n id: 'lineItemCountMax',\n label: t('sales.documents.list.filters.itemsMax', 'Max items'),\n type: 'text',\n },\n {\n id: 'totalNetMin',\n label: t('sales.documents.list.filters.totalNetMin', 'Min total (net)'),\n type: 'text',\n },\n {\n id: 'totalNetMax',\n label: t('sales.documents.list.filters.totalNetMax', 'Max total (net)'),\n type: 'text',\n },\n {\n id: 'totalGrossMin',\n label: t('sales.documents.list.filters.totalGrossMin', 'Min total (gross)'),\n type: 'text',\n },\n {\n id: 'totalGrossMax',\n label: t('sales.documents.list.filters.totalGrossMax', 'Max total (gross)'),\n type: 'text',\n },\n {\n id: 'customerId',\n label: t('sales.documents.list.filters.customer', 'Customer'),\n type: 'tags',\n options: customerOptions,\n loadOptions: loadCustomerOptions,\n placeholder: t('sales.documents.list.filters.customerPlaceholder', 'Search customers'),\n formatValue: (val: string) => {\n const match = customerOptions.find((opt) => opt.value === val)\n return match?.label ?? val\n },\n },\n {\n id: 'tagIds',\n label: t('sales.documents.list.filters.tags', 'Tags'),\n type: 'tags',\n options: tagOptions,\n loadOptions: loadTagOptions,\n formatValue: (val: string) => tagOptions.find((o) => o.value === val)?.label ?? val,\n formatDescription: (val: string) => tagOptions.find((o) => o.value === val)?.description ?? null,\n },\n ], [channelsEnabled, channelOptions, loadChannelOptions, customerOptions, loadCustomerOptions, loadTagOptions, tagOptions, t])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n if (search.trim()) params.set('search', search.trim())\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n const channelId = typeof filterValues.channelId === 'string' ? filterValues.channelId : ''\n if (channelId) params.set('channelId', channelId)\n const customerIds = Array.isArray(filterValues.customerId)\n ? filterValues.customerId\n .map((value) => (typeof value === 'string' ? value.trim() : String(value || '').trim()))\n .filter((value) => value.length > 0)\n : []\n if (customerIds.length > 0) {\n params.set('customerId', customerIds[0])\n }\n const date = filterValues.date\n if (date && typeof date === 'object') {\n if (date.from) params.set('dateFrom', date.from)\n if (date.to) params.set('dateTo', date.to)\n }\n const numberFilters: Array<[keyof FilterValues, string]> = [\n ['lineItemCountMin', 'lineItemCountMin'],\n ['lineItemCountMax', 'lineItemCountMax'],\n ['totalNetMin', 'totalNetMin'],\n ['totalNetMax', 'totalNetMax'],\n ['totalGrossMin', 'totalGrossMin'],\n ['totalGrossMax', 'totalGrossMax'],\n ]\n numberFilters.forEach(([key, queryKey]) => {\n const value = normalizeNumberInput((filterValues as any)[key])\n if (value != null) params.set(queryKey, String(value))\n })\n const tagIds = Array.isArray(filterValues.tagIds)\n ? filterValues.tagIds.map((value) => (typeof value === 'string' ? value.trim() : String(value || '').trim())).filter((v) => v.length > 0)\n : []\n if (tagIds.length > 0) {\n params.set('tagIds', tagIds.join(','))\n }\n Object.entries(filterValues).forEach(([key, value]) => {\n if (!key.startsWith('cf_') || value == null) return\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (normalized.length) params.set(key, normalized.join(','))\n } else if (typeof value === 'object') {\n return\n } else if (value !== '') {\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (stringValue) params.set(key, stringValue)\n }\n })\n return params.toString()\n }, [filterValues, page, search, sorting])\n\n const currentParams = React.useMemo(() => Object.fromEntries(new URLSearchParams(queryParams)), [queryParams])\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl(`sales/${resource}`, { ...currentParams, exportScope: 'view' }, format),\n },\n full: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl(`sales/${resource}`, { ...currentParams, exportScope: 'full', all: 'true' }, format),\n },\n }), [currentParams, resource])\n\n const mapApiDocument = React.useCallback(\n (item: Record<string, unknown>): SalesDocumentRow => {\n const doc = item as ApiDocument\n const id = typeof doc.id === 'string' ? doc.id : ''\n const number = kind === 'order'\n ? doc.orderNumber ?? (item as any)?.order_number ?? id\n : doc.quoteNumber ?? (item as any)?.quote_number ?? id\n const customerSnapshot = (doc.customerSnapshot ?? null) as CustomerSnapshot | null\n const customerName = resolveCustomerName(customerSnapshot, doc.customerEntityId ?? null)\n const customerEmail = resolveCustomerEmail(customerSnapshot)\n const totalNet = toNumber(doc.grandTotalNetAmount)\n const totalGross = toNumber(doc.grandTotalGrossAmount)\n const placedAt = doc.placedAt ?? null\n const validUntil = doc.validUntil ?? null\n const createdAt = doc.createdAt ?? null\n const date = placedAt ?? validUntil ?? createdAt ?? null\n return withDataTableNamespaces({\n id,\n number,\n status: doc.status ?? null,\n customerName,\n customerEmail,\n channelId: doc.channelId ?? null,\n lineItemCount: doc.lineItemCount ?? null,\n totalNet,\n totalGross,\n currency: doc.currencyCode ?? null,\n date,\n updatedAt: doc.updatedAt ?? null,\n }, item)\n },\n [kind]\n )\n\n const loadDocuments = React.useCallback(async () => {\n setLoading(true)\n setCacheStatus(null)\n try {\n const call = await apiCall<DocumentsResponse>(`/api/sales/${resource}?${queryParams}`)\n if (!call.ok) {\n flash(t('sales.documents.list.errors.load', 'Failed to load documents.'), 'error')\n setRows([])\n setTotal(0)\n setTotalPages(1)\n return\n }\n const payload = call.result ?? {}\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map((item) => mapApiDocument(item)))\n const count = typeof payload.total === 'number' ? payload.total : items.length\n setTotal(count)\n const pages = typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(count / PAGE_SIZE))\n setTotalPages(pages)\n setCacheStatus(call.cacheStatus ?? null)\n } catch (err) {\n logger.error('sales.documents.list', { err })\n flash(t('sales.documents.list.errors.load', 'Failed to load documents.'), 'error')\n } finally {\n setLoading(false)\n }\n }, [mapApiDocument, queryParams, resource, t])\n\n React.useEffect(() => {\n void loadDocuments()\n }, [loadDocuments, reloadToken, scopeVersion])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (row: SalesDocumentRow) => {\n const confirmMessage =\n kind === 'order'\n ? t(\n 'sales.documents.list.table.deleteOrderConfirm',\n 'Delete this sales order? Related shipments, payments, addresses, and items will be removed.'\n )\n : t(\n 'sales.documents.list.table.deleteQuoteConfirm',\n 'Delete this sales quote? Related addresses, comments, and items will be removed.'\n )\n const confirmed = await confirm({\n title: confirmMessage,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n const result = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () =>\n deleteCrud(`sales/${resource}`, row.id, {\n errorMessage: t('sales.documents.list.table.deleteError', 'Failed to delete document.'),\n }),\n )\n if (result.ok) {\n flash(\n kind === 'order'\n ? t('sales.documents.list.table.orderDeleted', 'Sales order deleted.')\n : t('sales.documents.list.table.quoteDeleted', 'Sales quote deleted.'),\n 'success'\n )\n handleRefresh()\n }\n } catch (err) {\n logger.error('sales.documents.delete', { err })\n flash(t('sales.documents.list.table.deleteError', 'Failed to delete document.'), 'error')\n }\n },\n [confirm, handleRefresh, kind, resource, t]\n )\n\n const handleRowClick = React.useCallback((row: SalesDocumentRow) => {\n router.push(`/backend/sales/${resource}/${row.id}?kind=${kind}`)\n }, [kind, resource, router])\n\n const columns = React.useMemo<ColumnDef<SalesDocumentRow>[]>(() => [\n {\n id: 'number',\n accessorKey: 'number',\n header: kind === 'order'\n ? t('sales.documents.list.table.order', 'Order')\n : t('sales.documents.list.table.quote', 'Quote'),\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-semibold\">{row.original.number}</span>\n {row.original.status ? (\n <DictionaryValue\n value={row.original.status}\n map={statusMap}\n fallback={<span className=\"text-xs text-muted-foreground\">{row.original.status}</span>}\n className=\"text-xs text-muted-foreground font-medium\"\n iconWrapperClassName=\"inline-flex h-5 w-5 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-3 w-3 rounded-full border border-border/70\"\n />\n ) : null}\n </div>\n ),\n meta: SALES_DOCUMENT_NUMBER_COLUMN_META,\n },\n {\n accessorKey: 'customerName',\n header: t('sales.documents.list.table.customer', 'Customer'),\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">\n {row.original.customerName ?? t('sales.documents.list.table.noCustomer', 'No customer')}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {row.original.customerEmail ?? t('sales.documents.list.table.noEmail', 'No email')}\n </span>\n </div>\n ),\n enableSorting: false,\n },\n ...(channelsEnabled ? [{\n accessorKey: 'channelId',\n header: t('sales.documents.list.table.channel', 'Channel'),\n cell: ({ row }) => {\n const channelId = row.original.channelId\n if (!channelId) return <span className=\"text-xs text-muted-foreground\">{t('sales.documents.list.table.unassigned', 'Unassigned')}</span>\n const channel = channelOptions.find((opt) => opt.value === channelId)\n return (\n <span className=\"text-sm\">{channel?.label ?? channelId}</span>\n )\n },\n enableSorting: false,\n } satisfies ColumnDef<SalesDocumentRow>] : []),\n {\n id: 'lineItemCount',\n accessorKey: 'lineItemCount',\n header: t('sales.documents.list.table.items', 'Items'),\n cell: ({ row }) => (\n <span className=\"text-sm font-semibold\">{typeof row.original.lineItemCount === 'number' ? row.original.lineItemCount : '\u2014'}</span>\n ),\n },\n {\n id: 'grandTotalNetAmount',\n accessorKey: 'totalNet',\n header: t('sales.documents.list.table.totalNet', 'Total (net)'),\n cell: ({ row }) => (\n <span className=\"text-sm\">{formatCurrency(row.original.totalNet ?? null, row.original.currency)}</span>\n ),\n },\n {\n id: 'grandTotalGrossAmount',\n accessorKey: 'totalGross',\n header: t('sales.documents.list.table.totalGross', 'Total (gross)'),\n cell: ({ row }) => (\n <span className=\"text-sm\">{formatCurrency(row.original.totalGross ?? null, row.original.currency)}</span>\n ),\n },\n {\n id: 'createdAt',\n accessorKey: 'date',\n header: t('sales.documents.list.table.date', 'Date'),\n cell: ({ row }) =>\n row.original.date\n ? <span className=\"text-xs text-muted-foreground\">{new Date(row.original.date).toLocaleString()}</span>\n : <span className=\"text-xs text-muted-foreground\">\u2014</span>,\n },\n ], [channelsEnabled, channelOptions, kind, statusMap, t])\n\n const emptyLabel = kind === 'order'\n ? t('sales.documents.list.table.emptyOrders', 'No orders yet.')\n : t('sales.documents.list.table.emptyQuotes', 'No quotes yet.')\n\n return (\n <Page>\n <PageBody>\n <DataTable<SalesDocumentRow>\n stickyActionsColumn\n title={(\n <div className=\"flex flex-col\">\n <span>{title}</span>\n <span className=\"text-sm font-normal text-muted-foreground\">{subtitle}</span>\n </div>\n )}\n actions={(\n <Button asChild>\n <Link href={`/backend/sales/documents/create?kind=${kind}`}>\n {t('sales.documents.create.title', 'Create sales document')}\n </Link>\n </Button>\n )}\n columns={columns}\n data={rows}\n sorting={sorting}\n onSortingChange={setSorting}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={\n kind === 'order'\n ? t('sales.documents.list.search.orders', 'Search orders\u2026')\n : t('sales.documents.list.search.quotes', 'Search quotes\u2026')\n }\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n entityId={entityId}\n exporter={exportConfig}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n cacheStatus,\n }}\n refreshButton={{\n label: t('sales.documents.list.table.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'open',\n label: t('sales.documents.list.table.open', 'Open'),\n href: `/backend/sales/${resource}/${row.id}?kind=${kind}`,\n },\n {\n id: 'delete',\n label:\n kind === 'order'\n ? t('sales.documents.list.table.deleteOrder', 'Delete order')\n : t('sales.documents.list.table.deleteQuote', 'Delete quote'),\n onSelect: () => handleDelete(row),\n },\n ]}\n />\n )}\n perspective={{ tableId: kind === 'order' ? 'sales.orders' : 'sales.quotes' }}\n onRowClick={handleRowClick}\n emptyState={\n <div className=\"py-10 text-center text-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n }\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nexport default SalesDocumentsTable\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { buildCrudExportUrl, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { E } from '#generated/entities.ids.generated'\nimport {\n DictionaryValue,\n type DictionaryMap,\n createDictionaryMap,\n normalizeDictionaryEntries,\n} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport { SALES_DOCUMENT_NUMBER_COLUMN_META } from './salesDocumentsColumns'\nimport { useSalesChannelsEnabled } from '../useSalesChannelsEnabled'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype SalesDocumentKind = 'order' | 'quote'\n\ntype FilterOption = { value: string; label: string; description?: string | null }\n\ntype CustomerSnapshot = {\n customer?: {\n displayName?: string | null\n primaryEmail?: string | null\n } | null\n contact?: {\n firstName?: string | null\n lastName?: string | null\n preferredName?: string | null\n } | null\n}\n\ntype ApiDocument = {\n id: string\n orderNumber?: string | null\n quoteNumber?: string | null\n status?: string | null\n customerEntityId?: string | null\n customerSnapshot?: Record<string, unknown> | null\n channelId?: string | null\n lineItemCount?: number | null\n grandTotalNetAmount?: number | null\n grandTotalGrossAmount?: number | null\n currencyCode?: string | null\n placedAt?: string | null\n validUntil?: string | null\n validFrom?: string | null\n createdAt?: string | null\n updatedAt?: string | null\n}\n\ntype DocumentsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype SalesDocumentRow = {\n id: string\n number: string\n status?: string | null\n customerName?: string | null\n customerEmail?: string | null\n channelId?: string | null\n lineItemCount?: number | null\n totalNet?: number | null\n totalGross?: number | null\n currency?: string | null\n date?: string | null\n updatedAt?: string | null\n}\n\nconst PAGE_SIZE = 20\n\nfunction resolveCustomerName(snapshot: CustomerSnapshot | null | undefined, fallback?: string | null) {\n if (!snapshot) return fallback ?? null\n const base = snapshot.customer?.displayName ?? null\n if (base) return base\n const contact = snapshot.contact\n if (contact) {\n const parts = [contact.preferredName, contact.firstName, contact.lastName].filter(\n (part) => part && part.trim().length\n ) as string[]\n if (parts.length) return parts.join(' ')\n }\n return fallback ?? null\n}\n\nfunction resolveCustomerEmail(snapshot: CustomerSnapshot | null | undefined) {\n if (!snapshot) return null\n if (snapshot.customer?.primaryEmail) return snapshot.customer.primaryEmail\n return null\n}\n\nfunction toNumber(value: unknown): number | null {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nfunction formatCurrency(amount: number | null | undefined, currency: string | null | undefined, fallback = '\u2014') {\n if (amount == null || Number.isNaN(amount)) return fallback\n try {\n if (currency && currency.trim().length) {\n const formatter = new Intl.NumberFormat(undefined, { style: 'currency', currency })\n return formatter.format(amount)\n }\n return new Intl.NumberFormat(undefined, { style: 'decimal', maximumFractionDigits: 2 }).format(amount)\n } catch {\n return String(amount)\n }\n}\n\nfunction mergeOptions(existing: FilterOption[], next: FilterOption[]): FilterOption[] {\n const map = new Map<string, FilterOption>()\n existing.forEach((opt) => map.set(opt.value, opt))\n next.forEach((opt) => map.set(opt.value, opt))\n return Array.from(map.values()).sort((a, b) => a.label.localeCompare(b.label))\n}\n\nfunction normalizeNumberInput(value: unknown): number | null {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n}\n\nexport function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {\n const t = useT()\n const { enabled: channelsEnabled } = useSalesChannelsEnabled()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<SalesDocumentRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'createdAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setLoading] = React.useState(false)\n const [cacheStatus, setCacheStatus] = React.useState<'hit' | 'miss' | null>(null)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [channelOptions, setChannelOptions] = React.useState<FilterOption[]>([])\n const [tagOptions, setTagOptions] = React.useState<FilterOption[]>([])\n const [customerOptions, setCustomerOptions] = React.useState<FilterOption[]>([])\n const [statusMap, setStatusMap] = React.useState<DictionaryMap>({})\n\n const resource = kind === 'order' ? 'orders' : 'quotes'\n const entityId = kind === 'order' ? E.sales.sales_order : E.sales.sales_quote\n const title = kind === 'order'\n ? t('sales.documents.list.ordersTitle', 'Sales orders')\n : t('sales.documents.list.quotesTitle', 'Sales quotes')\n const subtitle = t(\n 'sales.documents.list.subtitle',\n 'Review documents with customer context, totals, and channels.'\n )\n\n const fetchChannelOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '50' })\n if (query && query.trim()) params.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/sales/channels?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const name = typeof item?.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((opt): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n }, [])\n\n const fetchTagOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '50' })\n if (query && query.trim()) params.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/sales/tags?${params.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const label = typeof item?.label === 'string' ? item.label : null\n if (!id || !label) return null\n const description = typeof item?.description === 'string' ? item.description : null\n return { value: id, label, description }\n })\n .filter((opt): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n }, [])\n\n const fetchCustomerOptions = React.useCallback(async (query?: string): Promise<FilterOption[]> => {\n const params = new URLSearchParams({ page: '1', pageSize: '20' })\n if (query && query.trim().length) params.set('search', query.trim())\n try {\n const [people, companies] = await Promise.all([\n apiCall<{ items?: unknown[] }>(`/api/customers/people?${params.toString()}`),\n apiCall<{ items?: unknown[] }>(`/api/customers/companies?${params.toString()}`),\n ])\n const peopleItems = Array.isArray(people.result?.items) ? people.result?.items ?? [] : []\n const companyItems = Array.isArray(companies.result?.items) ? companies.result?.items ?? [] : []\n const parseOption = (item: any, kind: 'person' | 'company'): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n if (!id) return null\n const name =\n typeof item?.display_name === 'string' && item.display_name.trim().length\n ? item.display_name\n : typeof item?.name === 'string' && item.name.trim().length\n ? item.name\n : id\n const email =\n typeof item?.primary_email === 'string' && item.primary_email.trim().length\n ? item.primary_email.trim()\n : null\n const label = email ? `${name} (${email})` : name\n return { value: id, label }\n }\n const options = [...peopleItems.map((i) => parseOption(i, 'person')), ...companyItems.map((i) => parseOption(i, 'company'))]\n .filter((opt): opt is FilterOption => !!opt)\n return options\n } catch {\n return []\n }\n }, [])\n\n const loadStatusMap = React.useCallback(async () => {\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100' })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/order-statuses?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n const entries = normalizeDictionaryEntries(response.result?.items ?? [], { sort: false })\n setStatusMap(createDictionaryMap(entries))\n } catch (err) {\n logger.error('sales.documents.statuses.load', { err })\n setStatusMap({})\n }\n }, [])\n\n const loadChannelOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchChannelOptions(query)\n if (opts.length) setChannelOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchChannelOptions]\n )\n\n const loadTagOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchTagOptions(query)\n if (opts.length) setTagOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchTagOptions]\n )\n\n const loadCustomerOptions = React.useCallback(\n async (query?: string) => {\n const opts = await fetchCustomerOptions(query)\n if (opts.length) setCustomerOptions((prev) => mergeOptions(prev, opts))\n return opts\n },\n [fetchCustomerOptions]\n )\n\n React.useEffect(() => {\n if (channelsEnabled) loadChannelOptions().catch(() => {})\n loadTagOptions().catch(() => {})\n loadCustomerOptions().catch(() => {})\n loadStatusMap().catch(() => setStatusMap({}))\n }, [channelsEnabled, loadChannelOptions, loadCustomerOptions, loadStatusMap, loadTagOptions, scopeVersion])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n ...(channelsEnabled ? [{\n id: 'channelId',\n label: t('sales.documents.list.filters.channel', 'Channel'),\n type: 'select',\n options: channelOptions,\n loadOptions: loadChannelOptions,\n } satisfies FilterDef] : []),\n {\n id: 'date',\n label: t('sales.documents.list.filters.date', 'Date'),\n type: 'dateRange',\n },\n {\n id: 'lineItemCountMin',\n label: t('sales.documents.list.filters.itemsMin', 'Min items'),\n type: 'text',\n },\n {\n id: 'lineItemCountMax',\n label: t('sales.documents.list.filters.itemsMax', 'Max items'),\n type: 'text',\n },\n {\n id: 'totalNetMin',\n label: t('sales.documents.list.filters.totalNetMin', 'Min total (net)'),\n type: 'text',\n },\n {\n id: 'totalNetMax',\n label: t('sales.documents.list.filters.totalNetMax', 'Max total (net)'),\n type: 'text',\n },\n {\n id: 'totalGrossMin',\n label: t('sales.documents.list.filters.totalGrossMin', 'Min total (gross)'),\n type: 'text',\n },\n {\n id: 'totalGrossMax',\n label: t('sales.documents.list.filters.totalGrossMax', 'Max total (gross)'),\n type: 'text',\n },\n {\n id: 'customerId',\n label: t('sales.documents.list.filters.customer', 'Customer'),\n type: 'tags',\n options: customerOptions,\n loadOptions: loadCustomerOptions,\n placeholder: t('sales.documents.list.filters.customerPlaceholder', 'Search customers'),\n formatValue: (val: string) => {\n const match = customerOptions.find((opt) => opt.value === val)\n return match?.label ?? val\n },\n },\n {\n id: 'tagIds',\n label: t('sales.documents.list.filters.tags', 'Tags'),\n type: 'tags',\n options: tagOptions,\n loadOptions: loadTagOptions,\n formatValue: (val: string) => tagOptions.find((o) => o.value === val)?.label ?? val,\n formatDescription: (val: string) => tagOptions.find((o) => o.value === val)?.description ?? null,\n },\n ], [channelsEnabled, channelOptions, loadChannelOptions, customerOptions, loadCustomerOptions, loadTagOptions, tagOptions, t])\n\n const queryParams = React.useMemo(() => {\n const params = new URLSearchParams()\n params.set('page', String(page))\n params.set('pageSize', String(PAGE_SIZE))\n if (search.trim()) params.set('search', search.trim())\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n const channelId = typeof filterValues.channelId === 'string' ? filterValues.channelId : ''\n if (channelId) params.set('channelId', channelId)\n const customerIds = Array.isArray(filterValues.customerId)\n ? filterValues.customerId\n .map((value) => (typeof value === 'string' ? value.trim() : String(value || '').trim()))\n .filter((value) => value.length > 0)\n : []\n if (customerIds.length > 0) {\n params.set('customerId', customerIds[0])\n }\n const date = filterValues.date\n if (date && typeof date === 'object') {\n if (date.from) params.set('dateFrom', date.from)\n if (date.to) params.set('dateTo', date.to)\n }\n const numberFilters: Array<[keyof FilterValues, string]> = [\n ['lineItemCountMin', 'lineItemCountMin'],\n ['lineItemCountMax', 'lineItemCountMax'],\n ['totalNetMin', 'totalNetMin'],\n ['totalNetMax', 'totalNetMax'],\n ['totalGrossMin', 'totalGrossMin'],\n ['totalGrossMax', 'totalGrossMax'],\n ]\n numberFilters.forEach(([key, queryKey]) => {\n const value = normalizeNumberInput((filterValues as any)[key])\n if (value != null) params.set(queryKey, String(value))\n })\n const tagIds = Array.isArray(filterValues.tagIds)\n ? filterValues.tagIds.map((value) => (typeof value === 'string' ? value.trim() : String(value || '').trim())).filter((v) => v.length > 0)\n : []\n if (tagIds.length > 0) {\n params.set('tagIds', tagIds.join(','))\n }\n Object.entries(filterValues).forEach(([key, value]) => {\n if (!key.startsWith('cf_') || value == null) return\n if (Array.isArray(value)) {\n const normalized = value\n .map((item) => {\n if (item == null) return ''\n if (typeof item === 'string') return item.trim()\n return String(item).trim()\n })\n .filter((item) => item.length > 0)\n if (normalized.length) params.set(key, normalized.join(','))\n } else if (typeof value === 'object') {\n return\n } else if (value !== '') {\n const stringValue = typeof value === 'string' ? value.trim() : String(value)\n if (stringValue) params.set(key, stringValue)\n }\n })\n return params.toString()\n }, [filterValues, page, search, sorting])\n\n const currentParams = React.useMemo(() => Object.fromEntries(new URLSearchParams(queryParams)), [queryParams])\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl(`sales/${resource}`, { ...currentParams, exportScope: 'view' }, format),\n },\n full: {\n getUrl: (format: DataTableExportFormat) =>\n buildCrudExportUrl(`sales/${resource}`, { ...currentParams, exportScope: 'full', all: 'true' }, format),\n },\n }), [currentParams, resource])\n\n const mapApiDocument = React.useCallback(\n (item: Record<string, unknown>): SalesDocumentRow => {\n const doc = item as ApiDocument\n const id = typeof doc.id === 'string' ? doc.id : ''\n const number = kind === 'order'\n ? doc.orderNumber ?? (item as any)?.order_number ?? id\n : doc.quoteNumber ?? (item as any)?.quote_number ?? id\n const customerSnapshot = (doc.customerSnapshot ?? null) as CustomerSnapshot | null\n const customerName = resolveCustomerName(customerSnapshot, doc.customerEntityId ?? null)\n const customerEmail = resolveCustomerEmail(customerSnapshot)\n const totalNet = toNumber(doc.grandTotalNetAmount)\n const totalGross = toNumber(doc.grandTotalGrossAmount)\n const placedAt = doc.placedAt ?? null\n const validUntil = doc.validUntil ?? null\n const createdAt = doc.createdAt ?? null\n const date = placedAt ?? validUntil ?? createdAt ?? null\n return withDataTableNamespaces({\n id,\n number,\n status: doc.status ?? null,\n customerName,\n customerEmail,\n channelId: doc.channelId ?? null,\n lineItemCount: doc.lineItemCount ?? null,\n totalNet,\n totalGross,\n currency: doc.currencyCode ?? null,\n date,\n updatedAt: doc.updatedAt ?? null,\n }, item)\n },\n [kind]\n )\n\n const loadDocuments = React.useCallback(async () => {\n setLoading(true)\n setCacheStatus(null)\n try {\n const call = await apiCall<DocumentsResponse>(`/api/sales/${resource}?${queryParams}`)\n if (!call.ok) {\n flash(t('sales.documents.list.errors.load', 'Failed to load documents.'), 'error')\n setRows([])\n setTotal(0)\n setTotalPages(1)\n return\n }\n const payload = call.result ?? {}\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map((item) => mapApiDocument(item)))\n const count = typeof payload.total === 'number' ? payload.total : items.length\n setTotal(count)\n const pages = typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(count / PAGE_SIZE))\n setTotalPages(pages)\n setCacheStatus(call.cacheStatus ?? null)\n } catch (err) {\n logger.error('sales.documents.list', { err })\n flash(t('sales.documents.list.errors.load', 'Failed to load documents.'), 'error')\n } finally {\n setLoading(false)\n }\n }, [mapApiDocument, queryParams, resource, t])\n\n React.useEffect(() => {\n void loadDocuments()\n }, [loadDocuments, reloadToken, scopeVersion])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (row: SalesDocumentRow) => {\n const confirmMessage =\n kind === 'order'\n ? t(\n 'sales.documents.list.table.deleteOrderConfirm',\n 'Delete this sales order? Related shipments, payments, addresses, and items will be removed.'\n )\n : t(\n 'sales.documents.list.table.deleteQuoteConfirm',\n 'Delete this sales quote? Related addresses, comments, and items will be removed.'\n )\n const confirmed = await confirm({\n title: confirmMessage,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n const result = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () =>\n deleteCrud(`sales/${resource}`, row.id, {\n errorMessage: t('sales.documents.list.table.deleteError', 'Failed to delete document.'),\n }),\n )\n if (result.ok) {\n flash(\n kind === 'order'\n ? t('sales.documents.list.table.orderDeleted', 'Sales order deleted.')\n : t('sales.documents.list.table.quoteDeleted', 'Sales quote deleted.'),\n 'success'\n )\n handleRefresh()\n }\n } catch (err) {\n logger.error('sales.documents.delete', { err })\n flash(t('sales.documents.list.table.deleteError', 'Failed to delete document.'), 'error')\n }\n },\n [confirm, handleRefresh, kind, resource, t]\n )\n\n const handleRowClick = React.useCallback((row: SalesDocumentRow) => {\n router.push(`/backend/sales/${resource}/${row.id}?kind=${kind}`)\n }, [kind, resource, router])\n\n const columns = React.useMemo<ColumnDef<SalesDocumentRow>[]>(() => [\n {\n id: 'number',\n accessorKey: 'number',\n header: kind === 'order'\n ? t('sales.documents.list.table.order', 'Order')\n : t('sales.documents.list.table.quote', 'Quote'),\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-semibold\">{row.original.number}</span>\n {row.original.status ? (\n <DictionaryValue\n value={row.original.status}\n map={statusMap}\n fallback={<span className=\"text-xs text-muted-foreground\">{row.original.status}</span>}\n className=\"text-xs text-muted-foreground font-medium\"\n iconWrapperClassName=\"inline-flex h-5 w-5 items-center justify-center rounded bg-muted text-muted-foreground\"\n iconClassName=\"h-3.5 w-3.5\"\n colorClassName=\"h-3 w-3 rounded-full border border-border/70\"\n />\n ) : null}\n </div>\n ),\n meta: SALES_DOCUMENT_NUMBER_COLUMN_META,\n },\n {\n accessorKey: 'customerName',\n header: t('sales.documents.list.table.customer', 'Customer'),\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"text-sm font-medium\">\n {row.original.customerName ?? t('sales.documents.list.table.noCustomer', 'No customer')}\n </span>\n <span className=\"text-xs text-muted-foreground\">\n {row.original.customerEmail ?? t('sales.documents.list.table.noEmail', 'No email')}\n </span>\n </div>\n ),\n enableSorting: false,\n },\n ...(channelsEnabled ? [{\n accessorKey: 'channelId',\n header: t('sales.documents.list.table.channel', 'Channel'),\n cell: ({ row }) => {\n const channelId = row.original.channelId\n if (!channelId) return <span className=\"text-xs text-muted-foreground\">{t('sales.documents.list.table.unassigned', 'Unassigned')}</span>\n const channel = channelOptions.find((opt) => opt.value === channelId)\n return (\n <span className=\"text-sm\">{channel?.label ?? channelId}</span>\n )\n },\n enableSorting: false,\n } satisfies ColumnDef<SalesDocumentRow>] : []),\n {\n id: 'lineItemCount',\n accessorKey: 'lineItemCount',\n header: t('sales.documents.list.table.items', 'Items'),\n cell: ({ row }) => (\n <span className=\"text-sm font-semibold\">{typeof row.original.lineItemCount === 'number' ? row.original.lineItemCount : '\u2014'}</span>\n ),\n },\n {\n id: 'grandTotalNetAmount',\n accessorKey: 'totalNet',\n header: t('sales.documents.list.table.totalNet', 'Total (net)'),\n cell: ({ row }) => (\n <span className=\"text-sm\">{formatCurrency(row.original.totalNet ?? null, row.original.currency)}</span>\n ),\n },\n {\n id: 'grandTotalGrossAmount',\n accessorKey: 'totalGross',\n header: t('sales.documents.list.table.totalGross', 'Total (gross)'),\n cell: ({ row }) => (\n <span className=\"text-sm\">{formatCurrency(row.original.totalGross ?? null, row.original.currency)}</span>\n ),\n },\n {\n id: 'createdAt',\n accessorKey: 'date',\n header: t('sales.documents.list.table.date', 'Date'),\n cell: ({ row }) =>\n row.original.date\n ? <span className=\"text-xs text-muted-foreground\">{new Date(row.original.date).toLocaleString()}</span>\n : <span className=\"text-xs text-muted-foreground\">\u2014</span>,\n },\n ], [channelsEnabled, channelOptions, kind, statusMap, t])\n\n const emptyLabel = kind === 'order'\n ? t('sales.documents.list.table.emptyOrders', 'No orders yet.')\n : t('sales.documents.list.table.emptyQuotes', 'No quotes yet.')\n\n return (\n <Page>\n <PageBody>\n <DataTable<SalesDocumentRow>\n stickyFirstColumn\n stickyActionsColumn\n title={(\n <div className=\"flex flex-col\">\n <span>{title}</span>\n <span className=\"text-sm font-normal text-muted-foreground\">{subtitle}</span>\n </div>\n )}\n actions={(\n <Button asChild>\n <Link href={`/backend/sales/documents/create?kind=${kind}`}>\n {t('sales.documents.create.title', 'Create sales document')}\n </Link>\n </Button>\n )}\n columns={columns}\n data={rows}\n sorting={sorting}\n onSortingChange={setSorting}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={\n kind === 'order'\n ? t('sales.documents.list.search.orders', 'Search orders\u2026')\n : t('sales.documents.list.search.quotes', 'Search quotes\u2026')\n }\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n entityId={entityId}\n exporter={exportConfig}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n cacheStatus,\n }}\n refreshButton={{\n label: t('sales.documents.list.table.refresh', 'Refresh'),\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'open',\n label: t('sales.documents.list.table.open', 'Open'),\n href: `/backend/sales/${resource}/${row.id}?kind=${kind}`,\n },\n {\n id: 'delete',\n label:\n kind === 'order'\n ? t('sales.documents.list.table.deleteOrder', 'Delete order')\n : t('sales.documents.list.table.deleteQuote', 'Delete quote'),\n onSelect: () => handleDelete(row),\n },\n ]}\n />\n )}\n perspective={{ tableId: kind === 'order' ? 'sales.orders' : 'sales.quotes' }}\n onRowClick={handleRowClick}\n emptyState={\n <div className=\"py-10 text-center text-sm text-muted-foreground\">\n {emptyLabel}\n </div>\n }\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nexport default SalesDocumentsTable\n"],
5
+ "mappings": "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",
6
6
  "names": ["kind"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.6.7-develop.6568.1.9f57ffc393",
3
+ "version": "0.6.7-develop.6572.1.3d8e83062f",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -253,16 +253,16 @@
253
253
  "zod": "^4.4.3"
254
254
  },
255
255
  "peerDependencies": {
256
- "@open-mercato/ai-assistant": "0.6.7-develop.6568.1.9f57ffc393",
257
- "@open-mercato/shared": "0.6.7-develop.6568.1.9f57ffc393",
258
- "@open-mercato/ui": "0.6.7-develop.6568.1.9f57ffc393",
256
+ "@open-mercato/ai-assistant": "0.6.7-develop.6572.1.3d8e83062f",
257
+ "@open-mercato/shared": "0.6.7-develop.6572.1.3d8e83062f",
258
+ "@open-mercato/ui": "0.6.7-develop.6572.1.3d8e83062f",
259
259
  "react": "^19.0.0",
260
260
  "react-dom": "^19.0.0"
261
261
  },
262
262
  "devDependencies": {
263
- "@open-mercato/ai-assistant": "0.6.7-develop.6568.1.9f57ffc393",
264
- "@open-mercato/shared": "0.6.7-develop.6568.1.9f57ffc393",
265
- "@open-mercato/ui": "0.6.7-develop.6568.1.9f57ffc393",
263
+ "@open-mercato/ai-assistant": "0.6.7-develop.6572.1.3d8e83062f",
264
+ "@open-mercato/shared": "0.6.7-develop.6572.1.3d8e83062f",
265
+ "@open-mercato/ui": "0.6.7-develop.6572.1.3d8e83062f",
266
266
  "@testing-library/dom": "^10.4.1",
267
267
  "@testing-library/jest-dom": "^6.9.1",
268
268
  "@testing-library/react": "^16.3.1",
@@ -279,7 +279,7 @@ const createOrganizationCommand: CommandHandler<Record<string, unknown>, Organiz
279
279
  async execute(rawInput, ctx) {
280
280
  const { parsed, custom } = parseWithCustomFields(organizationCreateSchema, rawInput)
281
281
  const em = (ctx.container.resolve('em') as EntityManager)
282
- const tenantId = await enforceTenantSelection(ctx, parsed.tenantId ?? null)
282
+ const tenantId = await enforceTenantSelection(ctx, parsed.tenantId)
283
283
  if (!tenantId) throw new CrudHttpError(400, { error: 'Tenant scope required' })
284
284
 
285
285
  const parentId = parsed.parentId ?? null
@@ -91,7 +91,7 @@ export async function POST(req: Request) {
91
91
  { lockMode: LockMode.PESSIMISTIC_WRITE },
92
92
  tenantScope,
93
93
  )
94
- const quote = (await findQuoteByToken(hashedToken)) ?? (await findQuoteByToken(token))
94
+ const quote = await findQuoteByToken(hashedToken)
95
95
  if (!quote) {
96
96
  throw notFound(translate('sales.quotes.accept.notFound', 'Quote not found.'))
97
97
  }
@@ -32,15 +32,10 @@ export async function GET(req: Request, ctx: { params: { token: string } }) {
32
32
  const container = await createRequestContainer();
33
33
  const em = container.resolve("em") as EntityManager;
34
34
  const hashedToken = hashAuthToken(token);
35
- const quote =
36
- (await findOneWithDecryption(em, SalesQuote, {
37
- acceptanceToken: hashedToken,
38
- deletedAt: null,
39
- })) ??
40
- (await findOneWithDecryption(em, SalesQuote, {
41
- acceptanceToken: token,
42
- deletedAt: null,
43
- }));
35
+ const quote = await findOneWithDecryption(em, SalesQuote, {
36
+ acceptanceToken: hashedToken,
37
+ deletedAt: null,
38
+ });
44
39
  const { translate } = await resolveTranslations();
45
40
  if (!quote) {
46
41
  throw notFound(translate("sales.quotes.public.notFound", "Quote not found."));
@@ -673,6 +673,7 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
673
673
  <Page>
674
674
  <PageBody>
675
675
  <DataTable<SalesDocumentRow>
676
+ stickyFirstColumn
676
677
  stickyActionsColumn
677
678
  title={(
678
679
  <div className="flex flex-col">