@open-mercato/core 0.9.1-develop.7532.1.8eac7e198f → 0.9.1-develop.7536.1.f9a5776a07
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/auth/api/logout.js +8 -5
- package/dist/modules/auth/api/logout.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +5 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/commands/currencies.js +399 -137
- package/dist/modules/currencies/commands/currencies.js.map +2 -2
- package/dist/modules/currencies/lib/seeds.js +2 -0
- package/dist/modules/currencies/lib/seeds.js.map +2 -2
- package/dist/modules/customers/commands/companies.js +10 -3
- package/dist/modules/customers/commands/companies.js.map +2 -2
- package/dist/modules/customers/commands/interactionRestoreDetails.js +75 -0
- package/dist/modules/customers/commands/interactionRestoreDetails.js.map +7 -0
- package/dist/modules/customers/commands/people.js +10 -3
- package/dist/modules/customers/commands/people.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/auth/api/logout.ts +9 -5
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +5 -1
- package/src/modules/currencies/commands/currencies.ts +475 -168
- package/src/modules/currencies/i18n/de.json +4 -0
- package/src/modules/currencies/i18n/en.json +4 -0
- package/src/modules/currencies/i18n/es.json +4 -0
- package/src/modules/currencies/i18n/ko.json +4 -0
- package/src/modules/currencies/i18n/pl.json +4 -0
- package/src/modules/currencies/lib/seeds.ts +2 -0
- package/src/modules/customers/commands/companies.ts +16 -4
- package/src/modules/customers/commands/interactionRestoreDetails.ts +110 -0
- package/src/modules/customers/commands/people.ts +16 -4
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/currencies/commands/currencies.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { buildChanges, requireId, emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, conflict, isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { Currency, ExchangeRate } from '../data/entities'\nimport {\n currencyCreateSchema,\n currencyUpdateSchema,\n currencyDeleteSchema,\n type CurrencyCreateInput,\n type CurrencyUpdateInput,\n type CurrencyDeleteInput,\n} from '../data/validators'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { buildCurrencyCommandWhere, ensureCurrencyCommandScope } from './scope'\n\nconst currencyCrudEvents: CrudEventsConfig = {\n module: 'currencies',\n entity: 'currency',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype CurrencySnapshot = {\n id: string\n organizationId: string\n tenantId: string\n code: string\n name: string\n symbol: string | null\n decimalPlaces: number\n thousandsSeparator: string | null\n decimalSeparator: string | null\n isBase: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\ntype CurrencyUndoPayload = UndoPayload<CurrencySnapshot>\n\nasync function loadCurrencySnapshot(\n em: EntityManager,\n id: string,\n ctx: Parameters<typeof buildCurrencyCommandWhere>[0],\n): Promise<CurrencySnapshot | null> {\n const record = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id }),\n )\n if (!record) return null\n ensureCurrencyCommandScope(ctx, record)\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n code: record.code,\n name: record.name,\n symbol: record.symbol ?? null,\n decimalPlaces: record.decimalPlaces,\n thousandsSeparator: record.thousandsSeparator ?? null,\n decimalSeparator: record.decimalSeparator ?? null,\n isBase: !!record.isBase,\n isActive: !!record.isActive,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n }\n}\n\nasync function enforceBaseCurrency(\n em: EntityManager,\n currencyId: string,\n organizationId: string,\n tenantId: string\n): Promise<void> {\n await em.nativeUpdate(\n Currency,\n {\n organizationId,\n tenantId,\n id: { $ne: currencyId },\n isBase: true,\n deletedAt: null,\n },\n { isBase: false, updatedAt: new Date() }\n )\n}\n\nconst createCurrencyCommand: CommandHandler<CurrencyCreateInput, { currencyId: string }> = {\n id: 'currencies.currencies.create',\n async execute(input, ctx) {\n const parsed = currencyCreateSchema.parse(input)\n ensureCurrencyCommandScope(ctx, parsed)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n // Check for duplicate code\n const existing = await em.findOne(Currency, {\n code: parsed.code,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n deletedAt: null,\n })\n if (existing) {\n throw conflict('Currency code already exists for this organization.')\n }\n\n const now = new Date()\n const record = em.create(Currency, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n code: parsed.code,\n name: parsed.name,\n symbol: parsed.symbol ?? null,\n decimalPlaces: parsed.decimalPlaces ?? 2,\n thousandsSeparator: parsed.thousandsSeparator ?? null,\n decimalSeparator: parsed.decimalSeparator ?? null,\n isBase: parsed.isBase ?? false,\n isActive: parsed.isActive !== false,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n\n // Demote any existing base currency and insert the new record in one\n // transaction; a partial commit would leave zero or two base currencies.\n try {\n await withAtomicFlush(\n em,\n [\n () =>\n record.isBase\n ? enforceBaseCurrency(em, record.id, record.organizationId, record.tenantId)\n : undefined,\n ],\n { transaction: true },\n )\n } catch (err) {\n if (isUniqueViolation(err, 'currencies_code_scope_unique')) {\n throw conflict('Currency code already exists for this organization.')\n }\n throw err\n }\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return { currencyId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadCurrencySnapshot(em, result.currencyId, ctx)\n },\n buildLog: async ({ snapshots }) => {\n const after = snapshots.after as CurrencySnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('currencies.audit.create', 'Create currency'),\n resourceKind: 'currencies.currency',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: { undo: { after } },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const after = payload?.after ?? null\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(Currency, { id: after.id })\n if (!record) return\n record.deletedAt = new Date()\n record.isActive = false\n await em.flush()\n },\n redo: makeCreateRedo<Currency, CurrencySnapshot, CurrencyCreateInput, { currencyId: string }>({\n entityClass: Currency,\n buildResult: (entity) => ({ currencyId: entity.id }),\n events: currencyCrudEvents,\n afterRestore: async ({ em, entity }) => {\n if (entity.isBase) {\n await enforceBaseCurrency(em, entity.id, entity.organizationId, entity.tenantId)\n await em.flush()\n }\n },\n }),\n}\n\nconst updateCurrencyCommand: CommandHandler<CurrencyUpdateInput, { currencyId: string }> = {\n id: 'currencies.currencies.update',\n async prepare(input, ctx) {\n requireId(input.id, 'Currency ID is required')\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadCurrencySnapshot(em, input.id, ctx)\n return { before }\n },\n async execute(input, ctx) {\n const parsed = currencyUpdateSchema.parse(input)\n requireId(parsed.id, 'Currency ID is required')\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!record) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, record)\n\n // Check code uniqueness if changing code\n if (parsed.code && parsed.code !== record.code) {\n const existing = await em.findOne(Currency, {\n code: parsed.code,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n id: { $ne: record.id },\n deletedAt: null,\n })\n if (existing) {\n throw conflict('Currency code already exists for this organization.')\n }\n }\n\n const allChanges = buildChanges(record as unknown as Record<string, unknown>, parsed, [\n 'code',\n 'name',\n 'symbol',\n 'decimalPlaces',\n 'thousandsSeparator',\n 'decimalSeparator',\n 'isBase',\n 'isActive',\n ])\n const changes = Object.fromEntries(\n Object.entries(allChanges).filter(([, c]) => c.to !== undefined),\n ) as Record<string, { from: unknown; to: unknown }>\n\n if (Object.keys(changes).length === 0) {\n return { currencyId: record.id }\n }\n\n // Demote any existing base currency and persist the scalar changes in one\n // transaction; a partial commit would leave zero or two base currencies.\n // The scalar mutations live in the first phase so the per-phase flush issues\n // the pending changeset on the managed `record` before `enforceBaseCurrency`\n // runs its interleaved `nativeUpdate` (which would otherwise drop the pending\n // UPDATE under v7).\n await withAtomicFlush(\n em,\n [\n () => {\n for (const [key, change] of Object.entries(changes)) {\n ;(record as any)[key] = change.to\n }\n record.updatedAt = new Date()\n },\n () =>\n parsed.isBase === true && record.isBase\n ? enforceBaseCurrency(em, record.id, record.organizationId, record.tenantId)\n : undefined,\n ],\n { transaction: true },\n )\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return { currencyId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadCurrencySnapshot(em, result.currencyId, ctx)\n },\n buildLog: async ({ snapshots, result }) => {\n const before = snapshots.before as CurrencySnapshot | undefined\n const after = snapshots.after as CurrencySnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('currencies.audit.update', 'Update currency'),\n resourceKind: 'currencies.currency',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotBefore: before ?? undefined,\n snapshotAfter: after,\n payload: { undo: { before, after } },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const before = payload?.before ?? null\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(Currency, { id: before.id })\n if (!record) return\n Object.assign(record, {\n code: before.code,\n name: before.name,\n symbol: before.symbol,\n decimalPlaces: before.decimalPlaces,\n thousandsSeparator: before.thousandsSeparator,\n decimalSeparator: before.decimalSeparator,\n isBase: before.isBase,\n isActive: before.isActive,\n updatedAt: new Date(),\n })\n await em.flush()\n },\n}\n\nconst deleteCurrencyCommand: CommandHandler<CurrencyDeleteInput, { currencyId: string }> = {\n id: 'currencies.currencies.delete',\n async prepare(input, ctx) {\n requireId(input.id, 'Currency ID is required')\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadCurrencySnapshot(em, input.id, ctx)\n return { before }\n },\n async execute(input, ctx) {\n const parsed = currencyDeleteSchema.parse(input)\n requireId(parsed.id, 'Currency ID is required')\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!record) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, record)\n\n // Prevent deleting base currency\n if (record.isBase) {\n throw new CrudHttpError(400, { error: 'Cannot delete the base currency' })\n }\n\n // Prevent deleting currency with active exchange rates\n const activeRatesCount = await em.count(ExchangeRate, {\n $or: [\n { fromCurrencyCode: record.code },\n { toCurrencyCode: record.code },\n ],\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n deletedAt: null,\n isActive: true,\n })\n \n if (activeRatesCount > 0) {\n throw new CrudHttpError(400, { \n error: `Cannot delete currency ${record.code} because it has ${activeRatesCount} active exchange rate(s). Please delete or deactivate the exchange rates first.` \n })\n }\n\n record.deletedAt = new Date()\n record.isActive = false\n await em.flush()\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return { currencyId: record.id }\n },\n buildLog: async ({ snapshots, result }) => {\n const before = snapshots.before as CurrencySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('currencies.audit.delete', 'Delete currency'),\n resourceKind: 'currencies.currency',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: { undo: { before } },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const before = payload?.before ?? null\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(Currency, { id: before.id })\n if (!record) return\n record.deletedAt = null\n record.isActive = before.isActive\n record.updatedAt = new Date()\n await em.flush()\n },\n}\n\nregisterCommand(createCurrencyCommand)\nregisterCommand(updateCurrencyCommand)\nregisterCommand(deleteCurrencyCommand)\n\nexport { createCurrencyCommand, updateCurrencyCommand, deleteCurrencyCommand }\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { buildChanges, requireId, emitCrudSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { extractUndoPayload, type UndoPayload } from '@open-mercato/shared/lib/commands/undo'\nimport { resolveRedoSnapshot, restoreCreatedRow, reviveSnapshotSeed } from '@open-mercato/shared/lib/commands/redo'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError, conflict, isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { Currency, ExchangeRate } from '../data/entities'\nimport {\n currencyCreateSchema,\n currencyUpdateSchema,\n currencyDeleteSchema,\n type CurrencyCreateInput,\n type CurrencyUpdateInput,\n type CurrencyDeleteInput,\n} from '../data/validators'\nimport type { CrudEventsConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { buildCurrencyCommandWhere, ensureCurrencyCommandScope } from './scope'\n\nconst currencyCrudEvents: CrudEventsConfig = {\n module: 'currencies',\n entity: 'currency',\n persistent: true,\n buildPayload: (ctx) => ({\n id: ctx.identifiers.id,\n organizationId: ctx.identifiers.organizationId,\n tenantId: ctx.identifiers.tenantId,\n }),\n}\n\ntype CurrencySnapshot = {\n id: string\n organizationId: string\n tenantId: string\n code: string\n name: string\n symbol: string | null\n decimalPlaces: number\n thousandsSeparator: string | null\n decimalSeparator: string | null\n isBase: boolean\n isActive: boolean\n createdAt: string\n updatedAt: string\n}\n\nasync function loadCurrencySnapshot(\n em: EntityManager,\n id: string,\n ctx: Parameters<typeof buildCurrencyCommandWhere>[0],\n): Promise<CurrencySnapshot | null> {\n const record = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id }),\n )\n if (!record) return null\n ensureCurrencyCommandScope(ctx, record)\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n code: record.code,\n name: record.name,\n symbol: record.symbol ?? null,\n decimalPlaces: record.decimalPlaces,\n thousandsSeparator: record.thousandsSeparator ?? null,\n decimalSeparator: record.decimalSeparator ?? null,\n isBase: !!record.isBase,\n isActive: !!record.isActive,\n createdAt: record.createdAt.toISOString(),\n updatedAt: record.updatedAt.toISOString(),\n }\n}\n\ntype CurrencyScope = {\n tenantId: string\n organizationId: string\n}\n\ntype BaseCurrencyTransition = {\n promoted: boolean\n demotedBaseCurrencyIds: string[]\n}\n\ntype CurrencyCommandResult = {\n currencyId: string\n base?: BaseCurrencyTransition\n}\n\ntype CurrencyUndoPayload = UndoPayload<CurrencySnapshot> & {\n base?: BaseCurrencyTransition\n}\n\nconst NO_BASE_TRANSITION: BaseCurrencyTransition = { promoted: false, demotedBaseCurrencyIds: [] }\n\nconst BASE_CURRENCY_LOCK_SQL = 'select pg_advisory_xact_lock(hashtextextended(?, 0))'\n\nconst UPDATABLE_CURRENCY_FIELDS = [\n 'code',\n 'name',\n 'symbol',\n 'decimalPlaces',\n 'thousandsSeparator',\n 'decimalSeparator',\n 'isBase',\n 'isActive',\n] as const\n\nfunction baseCurrencyLockKey(scope: CurrencyScope): string {\n return `currencies:base:${scope.tenantId}:${scope.organizationId}`\n}\n\n/**\n * Serialize every currency write inside one tenant and organization so the\n * \"exactly one live base currency\" invariant is decided on fresh rows. The\n * transaction owns the lock, so PostgreSQL releases it on commit/rollback.\n */\nasync function lockBaseCurrencyScope(em: EntityManager, scope: CurrencyScope): Promise<void> {\n if (!em.isInTransaction()) {\n throw new Error('[internal] Currency base lock requires an active transaction')\n }\n await em.execute(BASE_CURRENCY_LOCK_SQL, [baseCurrencyLockKey(scope)])\n}\n\nasync function findLiveBaseCurrencyIds(\n em: EntityManager,\n scope: CurrencyScope,\n excludeId?: string,\n): Promise<string[]> {\n const rows = await em.find(\n Currency,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n isBase: true,\n deletedAt: null,\n ...(excludeId ? { id: { $ne: excludeId } } : {}),\n },\n { orderBy: { createdAt: 'asc', id: 'asc' } },\n )\n return rows.map((row) => row.id)\n}\n\nasync function setBaseFlag(\n em: EntityManager,\n scope: CurrencyScope,\n ids: string[],\n isBase: boolean,\n): Promise<void> {\n if (ids.length === 0) return\n await em.nativeUpdate(\n Currency,\n {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n id: { $in: ids },\n },\n { isBase, updatedAt: new Date() },\n )\n}\n\nasync function findFirstLivePredecessorId(\n em: EntityManager,\n scope: CurrencyScope,\n candidateIds: string[],\n): Promise<string | null> {\n if (candidateIds.length === 0) return null\n const rows = await em.find(Currency, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n id: { $in: candidateIds },\n deletedAt: null,\n })\n const liveIds = new Set(rows.map((row) => row.id))\n return candidateIds.find((id) => liveIds.has(id)) ?? null\n}\n\nasync function translatedHttpError(status: number, key: string, fallback: string): Promise<CrudHttpError> {\n const { translate } = await resolveTranslations()\n return new CrudHttpError(status, { error: translate(key, fallback) })\n}\n\nasync function resolvePredecessorOrRefuse(\n em: EntityManager,\n scope: CurrencyScope,\n candidateIds: string[],\n): Promise<string> {\n const predecessorId = await findFirstLivePredecessorId(em, scope, candidateIds)\n if (!predecessorId) {\n throw await translatedHttpError(\n 409,\n 'currencies.errors.undoWouldClearBase',\n \"This change can't be undone because it would leave the organization without a base currency.\",\n )\n }\n return predecessorId\n}\n\nfunction countActiveRatesForCode(em: EntityManager, scope: CurrencyScope, code: string): Promise<number> {\n return em.count(ExchangeRate, {\n $or: [\n { fromCurrencyCode: code },\n { toCurrencyCode: code },\n ],\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isActive: true,\n })\n}\n\nfunction readScopedSnapshotRecord(em: EntityManager, snapshot: CurrencySnapshot): Promise<Currency | null> {\n return em.findOne(Currency, {\n id: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n })\n}\n\nfunction scopeOf(record: CurrencyScope): CurrencyScope {\n return { tenantId: record.tenantId, organizationId: record.organizationId }\n}\n\nfunction omitIsBase(input: CurrencyUpdateInput): Partial<CurrencyUpdateInput> {\n const rest: Partial<CurrencyUpdateInput> = { ...input }\n delete rest.isBase\n return rest\n}\n\nfunction isPromotionByLegacyLog(payload: CurrencyUndoPayload | null): boolean {\n return payload?.before?.isBase === false && payload?.after?.isBase === true\n}\n\nfunction isDemotionByLegacyLog(payload: CurrencyUndoPayload | null): boolean {\n return !payload?.base && payload?.before?.isBase === true && payload?.after?.isBase === false\n}\n\nconst createCurrencyCommand: CommandHandler<CurrencyCreateInput, CurrencyCommandResult> = {\n id: 'currencies.currencies.create',\n async execute(input, ctx) {\n const parsed = currencyCreateSchema.parse(input)\n ensureCurrencyCommandScope(ctx, parsed)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = scopeOf(parsed)\n let demotedBaseCurrencyIds: string[] = []\n let record!: Currency\n\n try {\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const existing = await em.findOne(Currency, {\n code: parsed.code,\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n deletedAt: null,\n })\n if (existing) {\n throw conflict('Currency code already exists for this organization.')\n }\n if (parsed.isBase) {\n demotedBaseCurrencyIds = await findLiveBaseCurrencyIds(em, scope)\n await setBaseFlag(em, scope, demotedBaseCurrencyIds, false)\n }\n },\n () => {\n const now = new Date()\n record = em.create(Currency, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n code: parsed.code,\n name: parsed.name,\n symbol: parsed.symbol ?? null,\n decimalPlaces: parsed.decimalPlaces ?? 2,\n thousandsSeparator: parsed.thousandsSeparator ?? null,\n decimalSeparator: parsed.decimalSeparator ?? null,\n isBase: parsed.isBase ?? false,\n isActive: parsed.isActive !== false,\n createdAt: now,\n updatedAt: now,\n })\n em.persist(record)\n },\n ],\n { transaction: true },\n )\n } catch (err) {\n if (isUniqueViolation(err, 'currencies_code_scope_unique')) {\n throw conflict('Currency code already exists for this organization.')\n }\n throw err\n }\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return record.isBase\n ? { currencyId: record.id, base: { promoted: true, demotedBaseCurrencyIds } }\n : { currencyId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadCurrencySnapshot(em, result.currencyId, ctx)\n },\n buildLog: async ({ snapshots, result }) => {\n const after = snapshots.after as CurrencySnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('currencies.audit.create', 'Create currency'),\n resourceKind: 'currencies.currency',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotAfter: after,\n payload: { undo: { after, base: result?.base ?? NO_BASE_TRANSITION } },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const after = payload?.after ?? null\n if (!after) return\n const scope = scopeOf(after)\n const promoted = payload?.base ? payload.base.promoted : after.isBase\n const predecessorIds = payload?.base?.demotedBaseCurrencyIds ?? []\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record: Currency | null = null\n let restoredBaseId: string | null = null\n\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const current = await readScopedSnapshotRecord(em, after)\n if (!current || current.deletedAt) return\n const activeRatesCount = await countActiveRatesForCode(em, scope, current.code)\n if (activeRatesCount > 0) {\n throw await translatedHttpError(\n 409,\n 'currencies.errors.undoHasRates',\n \"This change can't be undone because exchange rates now use this currency. Delete or deactivate those exchange rates first.\",\n )\n }\n if (current.isBase) {\n restoredBaseId = await resolvePredecessorOrRefuse(em, scope, promoted ? predecessorIds : [])\n }\n record = current\n },\n () => {\n if (!record) return\n record.deletedAt = new Date()\n record.isActive = false\n record.isBase = false\n },\n () => (restoredBaseId ? setBaseFlag(em, scope, [restoredBaseId], true) : undefined),\n ],\n { transaction: true },\n )\n },\n redo: async ({ ctx, logEntry }) => {\n const snapshot = resolveRedoSnapshot<CurrencySnapshot>(logEntry)\n if (!snapshot || !snapshot.id) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for create command' })\n }\n const scope = scopeOf(snapshot)\n const isBase = snapshot.isBase === true\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let demotedBaseCurrencyIds: string[] = []\n let record!: Currency\n\n try {\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n if (isBase) {\n demotedBaseCurrencyIds = await findLiveBaseCurrencyIds(em, scope, snapshot.id)\n await setBaseFlag(em, scope, demotedBaseCurrencyIds, false)\n }\n },\n async () => {\n record = await restoreCreatedRow(\n em,\n Currency,\n snapshot.id,\n () => reviveSnapshotSeed(snapshot as unknown as Record<string, unknown>),\n (lookupEm) => readScopedSnapshotRecord(lookupEm, snapshot),\n )\n record.isBase = isBase\n },\n ],\n { transaction: true },\n )\n } catch (err) {\n if (isUniqueViolation(err)) {\n throw conflict('[internal] Cannot redo: a record with the same unique key already exists.')\n }\n throw err\n }\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return isBase\n ? { currencyId: record.id, base: { promoted: true, demotedBaseCurrencyIds } }\n : { currencyId: record.id }\n },\n}\n\nconst updateCurrencyCommand: CommandHandler<CurrencyUpdateInput, CurrencyCommandResult> = {\n id: 'currencies.currencies.update',\n async prepare(input, ctx) {\n requireId(input.id, 'Currency ID is required')\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadCurrencySnapshot(em, input.id, ctx)\n return { before }\n },\n async execute(input, ctx) {\n const parsed = currencyUpdateSchema.parse(input)\n requireId(parsed.id, 'Currency ID is required')\n\n const scopeRecord = await (ctx.container.resolve('em') as EntityManager).fork().findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!scopeRecord) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, scopeRecord)\n const scope = scopeOf(scopeRecord)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record!: Currency\n let changes: Record<string, { from: unknown; to: unknown }> = {}\n let promoted = false\n let demotedBaseCurrencyIds: string[] = []\n\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const current = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!current) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, current)\n record = current\n\n if (parsed.code && parsed.code !== record.code) {\n const existing = await em.findOne(Currency, {\n code: parsed.code,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n id: { $ne: record.id },\n deletedAt: null,\n })\n if (existing) {\n throw conflict('Currency code already exists for this organization.')\n }\n }\n\n if (parsed.isBase === false && record.isBase) {\n throw await translatedHttpError(\n 400,\n 'currencies.errors.baseCurrencyUnset',\n 'Choose another currency as the base instead of clearing it.',\n )\n }\n\n const allChanges = buildChanges(\n record as unknown as Record<string, unknown>,\n parsed,\n UPDATABLE_CURRENCY_FIELDS,\n )\n changes = Object.fromEntries(\n Object.entries(allChanges).filter(([, change]) => change.to !== undefined),\n ) as Record<string, { from: unknown; to: unknown }>\n\n promoted = changes.isBase?.to === true\n if (promoted) {\n demotedBaseCurrencyIds = await findLiveBaseCurrencyIds(em, scope, record.id)\n }\n },\n () => {\n if (Object.keys(changes).length === 0) return\n const assignments = Object.fromEntries(\n Object.entries(changes).map(([key, change]) => [key, change.to]),\n )\n Object.assign(record, assignments, { updatedAt: new Date() })\n },\n () => setBaseFlag(em, scope, demotedBaseCurrencyIds, false),\n ],\n { transaction: true },\n )\n\n const result: CurrencyCommandResult = promoted\n ? { currencyId: record.id, base: { promoted: true, demotedBaseCurrencyIds } }\n : { currencyId: record.id }\n if (Object.keys(changes).length === 0) {\n return result\n }\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return result\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return loadCurrencySnapshot(em, result.currencyId, ctx)\n },\n buildLog: async ({ input, snapshots, result }) => {\n const before = snapshots.before as CurrencySnapshot | undefined\n const after = snapshots.after as CurrencySnapshot | undefined\n if (!after) return null\n const { translate } = await resolveTranslations()\n const base = result?.base ?? NO_BASE_TRANSITION\n return {\n actionLabel: translate('currencies.audit.update', 'Update currency'),\n resourceKind: 'currencies.currency',\n resourceId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n snapshotBefore: before ?? undefined,\n snapshotAfter: after,\n payload: { undo: { before, after, base } },\n redoInput: base.promoted ? input : omitIsBase(input),\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const before = payload?.before ?? null\n if (!before) return\n const scope = scopeOf(before)\n const promoted = payload?.base ? payload.base.promoted : isPromotionByLegacyLog(payload)\n const predecessorIds = payload?.base?.demotedBaseCurrencyIds ?? []\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const demotedByLegacyLog = isDemotionByLegacyLog(payload)\n let record: Currency | null = null\n let restoredBaseId: string | null = null\n let repromote = false\n\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const current = await readScopedSnapshotRecord(em, before)\n if (!current) return\n if (promoted && current.isBase && !current.deletedAt) {\n restoredBaseId = await resolvePredecessorOrRefuse(em, scope, predecessorIds)\n }\n if (demotedByLegacyLog && !current.isBase && !current.deletedAt) {\n repromote = (await findLiveBaseCurrencyIds(em, scope)).length === 0\n }\n record = current\n },\n () => {\n if (!record) return\n Object.assign(record, {\n code: before.code,\n name: before.name,\n symbol: before.symbol,\n decimalPlaces: before.decimalPlaces,\n thousandsSeparator: before.thousandsSeparator,\n decimalSeparator: before.decimalSeparator,\n isActive: before.isActive,\n updatedAt: new Date(),\n })\n if (restoredBaseId) record.isBase = false\n if (repromote) record.isBase = true\n },\n () => (restoredBaseId ? setBaseFlag(em, scope, [restoredBaseId], true) : undefined),\n ],\n { transaction: true },\n )\n },\n}\n\nconst deleteCurrencyCommand: CommandHandler<CurrencyDeleteInput, { currencyId: string }> = {\n id: 'currencies.currencies.delete',\n async prepare(input, ctx) {\n requireId(input.id, 'Currency ID is required')\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadCurrencySnapshot(em, input.id, ctx)\n return { before }\n },\n async execute(input, ctx) {\n const parsed = currencyDeleteSchema.parse(input)\n requireId(parsed.id, 'Currency ID is required')\n\n const scopeRecord = await (ctx.container.resolve('em') as EntityManager).fork().findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!scopeRecord) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, scopeRecord)\n const scope = scopeOf(scopeRecord)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record!: Currency\n\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const current = await em.findOne(\n Currency,\n buildCurrencyCommandWhere<Currency>(ctx, { id: parsed.id }),\n )\n if (!current) {\n throw new CrudHttpError(404, { error: 'Currency not found' })\n }\n ensureCurrencyCommandScope(ctx, current)\n\n if (current.isBase) {\n throw new CrudHttpError(400, { error: 'Cannot delete the base currency' })\n }\n\n const activeRatesCount = await countActiveRatesForCode(em, scope, current.code)\n if (activeRatesCount > 0) {\n throw new CrudHttpError(400, {\n error: `Cannot delete currency ${current.code} because it has ${activeRatesCount} active exchange rate(s). Please delete or deactivate the exchange rates first.`,\n })\n }\n record = current\n },\n () => {\n record.deletedAt = new Date()\n record.isActive = false\n },\n ],\n { transaction: true },\n )\n\n const de = ctx.container.resolve('dataEngine') as DataEngine\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: currencyCrudEvents,\n })\n\n return { currencyId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as CurrencySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('currencies.audit.delete', 'Delete currency'),\n resourceKind: 'currencies.currency',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: { undo: { before } },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<CurrencyUndoPayload>(logEntry)\n const before = payload?.before ?? null\n if (!before) return\n const scope = scopeOf(before)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record: Currency | null = null\n let reviveAsNonBase = false\n\n await withAtomicFlush(\n em,\n [\n async () => {\n await lockBaseCurrencyScope(em, scope)\n const current = await readScopedSnapshotRecord(em, before)\n if (!current) return\n if (current.isBase) {\n const otherBaseIds = await findLiveBaseCurrencyIds(em, scope, current.id)\n reviveAsNonBase = otherBaseIds.length > 0\n }\n record = current\n },\n () => {\n if (!record) return\n record.deletedAt = null\n record.isActive = before.isActive\n if (reviveAsNonBase) record.isBase = false\n record.updatedAt = new Date()\n },\n ],\n { transaction: true },\n )\n },\n}\n\nregisterCommand(createCurrencyCommand)\nregisterCommand(updateCurrencyCommand)\nregisterCommand(deleteCurrencyCommand)\n\nexport { createCurrencyCommand, updateCurrencyCommand, deleteCurrencyCommand }\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -110,6 +110,7 @@ async function seedExampleCurrencies(em, scope) {
|
|
|
110
110
|
for (const entry of existingEntries) {
|
|
111
111
|
existingMap.set(entry.code, entry);
|
|
112
112
|
}
|
|
113
|
+
const hasLiveBase = existingEntries.some((entry) => entry.isBase && !entry.deletedAt);
|
|
113
114
|
let touched = false;
|
|
114
115
|
for (const curr of SEED_CURRENCIES) {
|
|
115
116
|
const current = existingMap.get(curr.code);
|
|
@@ -126,6 +127,7 @@ async function seedExampleCurrencies(em, scope) {
|
|
|
126
127
|
tenantId: scope.tenantId,
|
|
127
128
|
organizationId: scope.organizationId,
|
|
128
129
|
...curr,
|
|
130
|
+
isBase: curr.isBase && !hasLiveBase,
|
|
129
131
|
createdAt: /* @__PURE__ */ new Date(),
|
|
130
132
|
updatedAt: /* @__PURE__ */ new Date()
|
|
131
133
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/currencies/lib/seeds.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { Currency } from '../data/entities'\n\nexport type CurrencySeedScope = { tenantId: string; organizationId: string }\n\ntype CurrencySeed = {\n code: string\n name: string\n decimalPlaces: number\n symbol: string\n decimalSeparator: string\n thousandsSeparator: string\n isBase: boolean\n isActive: boolean\n}\n\nconst SEED_CURRENCIES: CurrencySeed[] = [\n {\n code: 'USD',\n name: 'US Dollar',\n decimalPlaces: 2,\n symbol: '$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: true,\n isActive: true,\n },\n {\n code: 'EUR',\n name: 'Euro',\n decimalPlaces: 2,\n symbol: '\u20AC',\n decimalSeparator: ',',\n thousandsSeparator: '.',\n isBase: false,\n isActive: true,\n },\n {\n code: 'JPY',\n name: 'Japanese Yen',\n decimalPlaces: 0,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'GBP',\n name: 'British Pound',\n decimalPlaces: 2,\n symbol: '\u00A3',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CHF',\n name: 'Swiss Franc',\n decimalPlaces: 2,\n symbol: 'Fr',\n decimalSeparator: '.',\n thousandsSeparator: \"'\",\n isBase: false,\n isActive: true,\n },\n {\n code: 'CAD',\n name: 'Canadian Dollar',\n decimalPlaces: 2,\n symbol: 'C$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'AUD',\n name: 'Australian Dollar',\n decimalPlaces: 2,\n symbol: 'A$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CNY',\n name: 'Chinese Yuan',\n decimalPlaces: 2,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CNH',\n name: 'Chinese Yuan (Offshore)',\n decimalPlaces: 2,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'PLN',\n name: 'Polish Zloty',\n decimalPlaces: 2,\n symbol: 'z\u0142',\n decimalSeparator: ',',\n thousandsSeparator: ' ',\n isBase: false,\n isActive: true,\n },\n]\n\nexport async function seedExampleCurrencies(em: EntityManager, scope: CurrencySeedScope): Promise<boolean> {\n const existingEntries = await em.find(Currency, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n const existingMap = new Map<string, Currency>()\n for (const entry of existingEntries) {\n existingMap.set(entry.code, entry)\n }\n\n let touched = false\n for (const curr of SEED_CURRENCIES) {\n const current = existingMap.get(curr.code)\n if (current) {\n if (current.name !== curr.name) {\n current.name = curr.name\n current.updatedAt = new Date()\n em.persist(current)\n touched = true\n }\n continue\n }\n const entry = em.create(Currency, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n ...curr,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(entry)\n touched = true\n }\n\n if (touched) {\n await em.flush()\n }\n return touched\n}\n"],
|
|
5
|
-
"mappings": "AACA,SAAS,gBAAgB;AAezB,MAAM,kBAAkC;AAAA,EACtC;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,MAAM;AAAA,IACN,eAAe;AAAA,IACf,QAAQ;AAAA,IACR,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AACF;AAEA,eAAsB,sBAAsB,IAAmB,OAA4C;AACzG,QAAM,kBAAkB,MAAM,GAAG,KAAK,UAAU;AAAA,IAC9C,UAAU,MAAM;AAAA,IAChB,gBAAgB,MAAM;AAAA,EACxB,CAAC;AACD,QAAM,cAAc,oBAAI,IAAsB;AAC9C,aAAW,SAAS,iBAAiB;AACnC,gBAAY,IAAI,MAAM,MAAM,KAAK;AAAA,EACnC;
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { Currency } from '../data/entities'\n\nexport type CurrencySeedScope = { tenantId: string; organizationId: string }\n\ntype CurrencySeed = {\n code: string\n name: string\n decimalPlaces: number\n symbol: string\n decimalSeparator: string\n thousandsSeparator: string\n isBase: boolean\n isActive: boolean\n}\n\nconst SEED_CURRENCIES: CurrencySeed[] = [\n {\n code: 'USD',\n name: 'US Dollar',\n decimalPlaces: 2,\n symbol: '$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: true,\n isActive: true,\n },\n {\n code: 'EUR',\n name: 'Euro',\n decimalPlaces: 2,\n symbol: '\u20AC',\n decimalSeparator: ',',\n thousandsSeparator: '.',\n isBase: false,\n isActive: true,\n },\n {\n code: 'JPY',\n name: 'Japanese Yen',\n decimalPlaces: 0,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'GBP',\n name: 'British Pound',\n decimalPlaces: 2,\n symbol: '\u00A3',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CHF',\n name: 'Swiss Franc',\n decimalPlaces: 2,\n symbol: 'Fr',\n decimalSeparator: '.',\n thousandsSeparator: \"'\",\n isBase: false,\n isActive: true,\n },\n {\n code: 'CAD',\n name: 'Canadian Dollar',\n decimalPlaces: 2,\n symbol: 'C$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'AUD',\n name: 'Australian Dollar',\n decimalPlaces: 2,\n symbol: 'A$',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CNY',\n name: 'Chinese Yuan',\n decimalPlaces: 2,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'CNH',\n name: 'Chinese Yuan (Offshore)',\n decimalPlaces: 2,\n symbol: '\u00A5',\n decimalSeparator: '.',\n thousandsSeparator: ',',\n isBase: false,\n isActive: true,\n },\n {\n code: 'PLN',\n name: 'Polish Zloty',\n decimalPlaces: 2,\n symbol: 'z\u0142',\n decimalSeparator: ',',\n thousandsSeparator: ' ',\n isBase: false,\n isActive: true,\n },\n]\n\nexport async function seedExampleCurrencies(em: EntityManager, scope: CurrencySeedScope): Promise<boolean> {\n const existingEntries = await em.find(Currency, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n })\n const existingMap = new Map<string, Currency>()\n for (const entry of existingEntries) {\n existingMap.set(entry.code, entry)\n }\n const hasLiveBase = existingEntries.some((entry) => entry.isBase && !entry.deletedAt)\n\n let touched = false\n for (const curr of SEED_CURRENCIES) {\n const current = existingMap.get(curr.code)\n if (current) {\n if (current.name !== curr.name) {\n current.name = curr.name\n current.updatedAt = new Date()\n em.persist(current)\n touched = true\n }\n continue\n }\n const entry = em.create(Currency, {\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n ...curr,\n isBase: curr.isBase && !hasLiveBase,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(entry)\n touched = true\n }\n\n if (touched) {\n await em.flush()\n }\n return touched\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,6 +22,11 @@ import {
|
|
|
22
22
|
CustomerPersonProfile,
|
|
23
23
|
CustomerTagAssignment
|
|
24
24
|
} from "../data/entities.js";
|
|
25
|
+
import {
|
|
26
|
+
captureInteractionRestoreDetails,
|
|
27
|
+
omitInteractionRestoreDetails,
|
|
28
|
+
restoreInteractionRestoreDetails
|
|
29
|
+
} from "./interactionRestoreDetails.js";
|
|
25
30
|
import {
|
|
26
31
|
companyCreateSchema,
|
|
27
32
|
companyUpdateSchema
|
|
@@ -98,7 +103,7 @@ function companyEntityIndexEntry(entity) {
|
|
|
98
103
|
organizationId: entity.organizationId
|
|
99
104
|
};
|
|
100
105
|
}
|
|
101
|
-
async function loadCompanySnapshot(em, id) {
|
|
106
|
+
async function loadCompanySnapshot(em, id, options = {}) {
|
|
102
107
|
const entity = await em.findOne(CustomerEntity, { id, deletedAt: null });
|
|
103
108
|
if (!entity || entity.kind !== "company") return null;
|
|
104
109
|
const profile = await em.findOne(CustomerCompanyProfile, { entity });
|
|
@@ -248,6 +253,7 @@ async function loadCompanySnapshot(em, id) {
|
|
|
248
253
|
createdAt: interaction.createdAt,
|
|
249
254
|
updatedAt: interaction.updatedAt,
|
|
250
255
|
deletedAt: interaction.deletedAt ?? null,
|
|
256
|
+
...options.includeInteractionRestoreDetails ? captureInteractionRestoreDetails(interaction) : {},
|
|
251
257
|
custom: await loadCustomFieldSnapshot(em, {
|
|
252
258
|
entityId: INTERACTION_ENTITY_ID,
|
|
253
259
|
recordId: interaction.id,
|
|
@@ -792,7 +798,7 @@ const deleteCompanyCommand = {
|
|
|
792
798
|
async prepare(input, ctx) {
|
|
793
799
|
const id = requireId(input, "Company id required");
|
|
794
800
|
const em = ctx.container.resolve("em");
|
|
795
|
-
const snapshot = await loadCompanySnapshot(em, id);
|
|
801
|
+
const snapshot = await loadCompanySnapshot(em, id, { includeInteractionRestoreDetails: true });
|
|
796
802
|
return snapshot ? { before: snapshot } : {};
|
|
797
803
|
},
|
|
798
804
|
async execute(input, ctx) {
|
|
@@ -966,7 +972,7 @@ const deleteCompanyCommand = {
|
|
|
966
972
|
resourceId: before.entity.id,
|
|
967
973
|
tenantId: before.entity.tenantId,
|
|
968
974
|
organizationId: before.entity.organizationId,
|
|
969
|
-
snapshotBefore: before,
|
|
975
|
+
snapshotBefore: omitInteractionRestoreDetails(before),
|
|
970
976
|
payload: {
|
|
971
977
|
undo: {
|
|
972
978
|
before
|
|
@@ -1193,6 +1199,7 @@ const deleteCompanyCommand = {
|
|
|
1193
1199
|
source: interaction.source,
|
|
1194
1200
|
appearanceIcon: interaction.appearanceIcon,
|
|
1195
1201
|
appearanceColor: interaction.appearanceColor,
|
|
1202
|
+
...restoreInteractionRestoreDetails(interaction),
|
|
1196
1203
|
createdAt: interaction.createdAt,
|
|
1197
1204
|
updatedAt: interaction.updatedAt,
|
|
1198
1205
|
deletedAt: interaction.deletedAt
|