@open-mercato/checkout 0.6.5-develop.4708.1.93cb8395bd → 0.6.5-develop.4732.1.732f6c67a5
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/dist/modules/checkout/commands/links.js +54 -0
- package/dist/modules/checkout/commands/links.js.map +2 -2
- package/dist/modules/checkout/commands/templates.js +40 -0
- package/dist/modules/checkout/commands/templates.js.map +2 -2
- package/jest.config.cjs +2 -0
- package/package.json +5 -5
- package/src/modules/checkout/commands/__tests__/redo-coverage.test.ts +21 -0
- package/src/modules/checkout/commands/links.ts +54 -0
- package/src/modules/checkout/commands/templates.ts +40 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
2
2
|
import { buildCustomFieldResetMap, loadCustomFieldSnapshot } from "@open-mercato/shared/lib/commands/customFieldSnapshots";
|
|
3
3
|
import { setCustomFieldsIfAny } from "@open-mercato/shared/lib/commands/helpers";
|
|
4
|
+
import { resolveRedoSnapshot } from "@open-mercato/shared/lib/commands/redo";
|
|
4
5
|
import { loadCustomFieldValues } from "@open-mercato/shared/lib/crud/custom-fields";
|
|
5
6
|
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
6
7
|
import { enforceCommandOptimisticLock } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
|
|
@@ -181,6 +182,59 @@ const createLinkCommand = {
|
|
|
181
182
|
if (!link) return;
|
|
182
183
|
link.deletedAt = /* @__PURE__ */ new Date();
|
|
183
184
|
await em.flush();
|
|
185
|
+
},
|
|
186
|
+
redo: async ({ logEntry, ctx }) => {
|
|
187
|
+
const after = resolveRedoSnapshot(logEntry);
|
|
188
|
+
if (!after) throw new CrudHttpError(400, { error: "[internal] redo snapshot unavailable for checkout link create" });
|
|
189
|
+
const em = ctx.container.resolve("em");
|
|
190
|
+
const dataEngine = ctx.container.resolve("dataEngine");
|
|
191
|
+
let link = await findOneWithDecryption(
|
|
192
|
+
em,
|
|
193
|
+
CheckoutLink,
|
|
194
|
+
{ id: after.id },
|
|
195
|
+
{},
|
|
196
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
197
|
+
);
|
|
198
|
+
if (link) {
|
|
199
|
+
restoreLinkFromSnapshot(link, after);
|
|
200
|
+
link.deletedAt = null;
|
|
201
|
+
link.slug = await resolveRestoredLinkSlug(em, after);
|
|
202
|
+
} else {
|
|
203
|
+
link = em.create(CheckoutLink, {
|
|
204
|
+
...createLinkFromSnapshot(after),
|
|
205
|
+
slug: await resolveRestoredLinkSlug(em, after)
|
|
206
|
+
});
|
|
207
|
+
em.persist(link);
|
|
208
|
+
}
|
|
209
|
+
await em.flush();
|
|
210
|
+
const reset = buildCustomFieldResetMap(after.custom, void 0);
|
|
211
|
+
if (Object.keys(reset).length) {
|
|
212
|
+
await setCustomFieldsIfAny({
|
|
213
|
+
dataEngine,
|
|
214
|
+
entityId: CHECKOUT_ENTITY_IDS.link,
|
|
215
|
+
recordId: after.id,
|
|
216
|
+
tenantId: after.tenantId,
|
|
217
|
+
organizationId: after.organizationId,
|
|
218
|
+
values: reset,
|
|
219
|
+
notify: false
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
await emitCheckoutEvent("checkout.link.created", {
|
|
223
|
+
id: link.id,
|
|
224
|
+
slug: link.slug,
|
|
225
|
+
status: link.status,
|
|
226
|
+
tenantId: after.tenantId,
|
|
227
|
+
organizationId: after.organizationId
|
|
228
|
+
}).catch(() => void 0);
|
|
229
|
+
if (link.status === "active") {
|
|
230
|
+
await emitCheckoutEvent("checkout.link.published", {
|
|
231
|
+
id: link.id,
|
|
232
|
+
slug: link.slug,
|
|
233
|
+
tenantId: after.tenantId,
|
|
234
|
+
organizationId: after.organizationId
|
|
235
|
+
}).catch(() => void 0);
|
|
236
|
+
}
|
|
237
|
+
return { id: link.id, slug: link.slug };
|
|
184
238
|
}
|
|
185
239
|
};
|
|
186
240
|
const updateLinkCommand = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/checkout/commands/links.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate, CheckoutTransaction } from '../data/entities'\nimport { createLinkSchema, updateLinkSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n ensureUniqueSlug,\n hashCheckoutPassword,\n isCheckoutLinkPublic,\n parseCheckoutInput,\n pickExplicitParsedOverrides,\n resolveLoadedCheckoutCustomFields,\n serializeTemplateOrLink,\n toMoneyString,\n toTemplateOrLinkMutationInput,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n captureLinkSnapshot,\n createLinkFromSnapshot,\n extractUndoPayload,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutLinkSnapshot,\n} from './shared'\n\nconst ACTIVE_TRANSACTION_STATUSES = ['pending', 'processing']\n\ntype CheckoutLinkUndoPayload = {\n before?: CheckoutLinkSnapshot | null\n after?: CheckoutLinkSnapshot | null\n}\n\nasync function resolveRestoredLinkSlug(\n em: EntityManager,\n snapshot: CheckoutLinkSnapshot,\n): Promise<string> {\n return ensureUniqueSlug(\n em,\n {\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n },\n snapshot.slug,\n snapshot.title ?? snapshot.name,\n snapshot.id,\n )\n}\n\nconst createLinkCommand: CommandHandler<Record<string, unknown>, { id: string; slug: string }> = {\n id: 'checkout.link.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n\n let sourceValues = parsed\n let templateCustomFields: Record<string, unknown> = {}\n if (parsed.templateId) {\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n sourceValues = toTemplateOrLinkMutationInput(template, {\n ...pickExplicitParsedOverrides(rawInput, parsed),\n templateId: template.id,\n })\n const loaded = await loadCustomFieldValues({\n em,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordIds: [template.id],\n tenantIdByRecord: { [template.id]: scope.tenantId },\n organizationIdByRecord: { [template.id]: scope.organizationId },\n })\n templateCustomFields = resolveLoadedCheckoutCustomFields(loaded[template.id])\n }\n\n validateDescriptorCurrencies(sourceValues.gatewayProviderKey ?? null, deriveConfiguredCurrencies(sourceValues))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(sourceValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(sourceValues.status) && !sourceValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = await ensureUniqueSlug(\n em,\n scope,\n sourceValues.slug ?? null,\n sourceValues.title ?? sourceValues.name,\n )\n const link = em.create(CheckoutLink, {\n ...sourceValues,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n completionCount: 0,\n activeReservationCount: 0,\n isLocked: false,\n fixedPriceAmount: toMoneyString(sourceValues.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(sourceValues.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(sourceValues.customAmountMin),\n customAmountMax: toMoneyString(sourceValues.customAmountMax),\n slug,\n passwordHash: await hashCheckoutPassword(sourceValues.password),\n } as any)\n em.persist(link)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: { ...templateCustomFields, ...customFields },\n })\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { id: result.id })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.create', 'Create pay link'),\n resourceKind: 'checkout.link',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const link = await em.findOne(CheckoutLink, { id: after.id })\n if (!link) return\n link.deletedAt = new Date()\n await em.flush()\n },\n}\n\nconst updateLinkCommand: CommandHandler<Record<string, unknown>, { ok: true; slug: string }> = {\n id: 'checkout.link.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n if (link.isLocked) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be edited' })\n }\n const nextValues = toTemplateOrLinkMutationInput(link, parsed)\n validateDescriptorCurrencies(\n parsed.gatewayProviderKey ?? link.gatewayProviderKey ?? null,\n deriveConfiguredCurrencies(nextValues),\n )\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(nextValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(nextValues.status) && !nextValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = parsed.slug !== undefined || parsed.name !== undefined || parsed.title !== undefined\n ? await ensureUniqueSlug(em, scope, parsed.slug ?? link.slug, parsed.title ?? parsed.name ?? link.title ?? link.name, link.id)\n : link.slug\n const passwordHash = parsed.password !== undefined ? await hashCheckoutPassword(parsed.password) : link.passwordHash\n const previousStatus = link.status\n Object.assign(link, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : link.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : link.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : link.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : link.customAmountMax,\n slug,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.link.updated', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n previousStatus,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (previousStatus !== 'active' && link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { slug: result.slug, deletedAt: null })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ snapshots, result }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.update', 'Update pay link'),\n resourceKind: 'checkout.link',\n resourceId: after?.id ?? before?.id ?? null,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n context: result.slug ? { slug: result.slug } : null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await em.findOne(CheckoutLink, { id: before.id, deletedAt: null })\n if (!link) return\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nconst deleteLinkCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.link.delete',\n async prepare(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const activeCount = await em.count(CheckoutTransaction, {\n linkId: link.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: { $in: ACTIVE_TRANSACTION_STATUSES as Array<CheckoutTransaction['status']> },\n })\n if (activeCount > 0) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be deleted' })\n }\n link.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.link.deleted', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.delete', 'Delete pay link'),\n resourceKind: 'checkout.link',\n resourceId: before?.id ?? readCommandId(input, 'Link id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await em.findOne(CheckoutLink, { id: before.id })\n if (link) {\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(before),\n slug: await resolveRestoredLinkSlug(em, before),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createLinkCommand)\nregisterCommand(updateLinkCommand)\nregisterCommand(deleteLinkCommand)\n\nexport function serializeLinkRecord(record: CheckoutLink) {\n return serializeTemplateOrLink(record)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate, CheckoutTransaction } from '../data/entities'\nimport { createLinkSchema, updateLinkSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n ensureUniqueSlug,\n hashCheckoutPassword,\n isCheckoutLinkPublic,\n parseCheckoutInput,\n pickExplicitParsedOverrides,\n resolveLoadedCheckoutCustomFields,\n serializeTemplateOrLink,\n toMoneyString,\n toTemplateOrLinkMutationInput,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n captureLinkSnapshot,\n createLinkFromSnapshot,\n extractUndoPayload,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutLinkSnapshot,\n} from './shared'\n\nconst ACTIVE_TRANSACTION_STATUSES = ['pending', 'processing']\n\ntype CheckoutLinkUndoPayload = {\n before?: CheckoutLinkSnapshot | null\n after?: CheckoutLinkSnapshot | null\n}\n\nasync function resolveRestoredLinkSlug(\n em: EntityManager,\n snapshot: CheckoutLinkSnapshot,\n): Promise<string> {\n return ensureUniqueSlug(\n em,\n {\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n },\n snapshot.slug,\n snapshot.title ?? snapshot.name,\n snapshot.id,\n )\n}\n\nconst createLinkCommand: CommandHandler<Record<string, unknown>, { id: string; slug: string }> = {\n id: 'checkout.link.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n\n let sourceValues = parsed\n let templateCustomFields: Record<string, unknown> = {}\n if (parsed.templateId) {\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n sourceValues = toTemplateOrLinkMutationInput(template, {\n ...pickExplicitParsedOverrides(rawInput, parsed),\n templateId: template.id,\n })\n const loaded = await loadCustomFieldValues({\n em,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordIds: [template.id],\n tenantIdByRecord: { [template.id]: scope.tenantId },\n organizationIdByRecord: { [template.id]: scope.organizationId },\n })\n templateCustomFields = resolveLoadedCheckoutCustomFields(loaded[template.id])\n }\n\n validateDescriptorCurrencies(sourceValues.gatewayProviderKey ?? null, deriveConfiguredCurrencies(sourceValues))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(sourceValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(sourceValues.status) && !sourceValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = await ensureUniqueSlug(\n em,\n scope,\n sourceValues.slug ?? null,\n sourceValues.title ?? sourceValues.name,\n )\n const link = em.create(CheckoutLink, {\n ...sourceValues,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n completionCount: 0,\n activeReservationCount: 0,\n isLocked: false,\n fixedPriceAmount: toMoneyString(sourceValues.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(sourceValues.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(sourceValues.customAmountMin),\n customAmountMax: toMoneyString(sourceValues.customAmountMax),\n slug,\n passwordHash: await hashCheckoutPassword(sourceValues.password),\n } as any)\n em.persist(link)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: { ...templateCustomFields, ...customFields },\n })\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { id: result.id })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.create', 'Create pay link'),\n resourceKind: 'checkout.link',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const link = await em.findOne(CheckoutLink, { id: after.id })\n if (!link) return\n link.deletedAt = new Date()\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<CheckoutLinkSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout link create' })\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await findOneWithDecryption(\n em,\n CheckoutLink,\n { id: after.id },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n if (link) {\n restoreLinkFromSnapshot(link, after)\n link.deletedAt = null\n link.slug = await resolveRestoredLinkSlug(em, after)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(after),\n slug: await resolveRestoredLinkSlug(em, after),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n await emitCheckoutEvent('checkout.link.created', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n if (link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n }\n return { id: link.id, slug: link.slug }\n },\n}\n\nconst updateLinkCommand: CommandHandler<Record<string, unknown>, { ok: true; slug: string }> = {\n id: 'checkout.link.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateLinkSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n if (link.isLocked) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be edited' })\n }\n const nextValues = toTemplateOrLinkMutationInput(link, parsed)\n validateDescriptorCurrencies(\n parsed.gatewayProviderKey ?? link.gatewayProviderKey ?? null,\n deriveConfiguredCurrencies(nextValues),\n )\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(nextValues.gatewayProviderKey ?? null, descriptorService, scope)\n if (isCheckoutLinkPublic(nextValues.status) && !nextValues.gatewayProviderKey) {\n throw new CrudHttpError(422, { error: 'A payment gateway must be configured before this link can be published' })\n }\n const slug = parsed.slug !== undefined || parsed.name !== undefined || parsed.title !== undefined\n ? await ensureUniqueSlug(em, scope, parsed.slug ?? link.slug, parsed.title ?? parsed.name ?? link.title ?? link.name, link.id)\n : link.slug\n const passwordHash = parsed.password !== undefined ? await hashCheckoutPassword(parsed.password) : link.passwordHash\n const previousStatus = link.status\n Object.assign(link, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : link.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : link.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : link.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : link.customAmountMax,\n slug,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.link.updated', {\n id: link.id,\n slug: link.slug,\n status: link.status,\n previousStatus,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n if (previousStatus !== 'active' && link.status === 'active') {\n await emitCheckoutEvent('checkout.link.published', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n }\n return { ok: true, slug: link.slug }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const link = await findOneWithDecryption(em, CheckoutLink, { slug: result.slug, deletedAt: null })\n if (!link) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return captureLinkSnapshot(link, custom)\n },\n buildLog: async ({ snapshots, result }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n const after = snapshots.after as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.update', 'Update pay link'),\n resourceKind: 'checkout.link',\n resourceId: after?.id ?? before?.id ?? null,\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n context: result.slug ? { slug: result.slug } : null,\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const link = await em.findOne(CheckoutLink, { id: before.id, deletedAt: null })\n if (!link) return\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nconst deleteLinkCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.link.delete',\n async prepare(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n return { before: captureLinkSnapshot(link, custom) }\n },\n async execute(rawInput, ctx) {\n const linkId = readCommandId(rawInput, 'Link id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const link = await findOneWithDecryption(em, CheckoutLink, {\n id: linkId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!link) throw new CrudHttpError(404, { error: 'Link not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.link',\n resourceId: link.id,\n current: link.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const activeCount = await em.count(CheckoutTransaction, {\n linkId: link.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n status: { $in: ACTIVE_TRANSACTION_STATUSES as Array<CheckoutTransaction['status']> },\n })\n if (activeCount > 0) {\n throw new CrudHttpError(422, { error: 'This link has active transactions and cannot be deleted' })\n }\n link.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.link.deleted', {\n id: link.id,\n slug: link.slug,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutLinkSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.links.delete', 'Delete pay link'),\n resourceKind: 'checkout.link',\n resourceId: before?.id ?? readCommandId(input, 'Link id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutLinkUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutLinkUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let link = await em.findOne(CheckoutLink, { id: before.id })\n if (link) {\n restoreLinkFromSnapshot(link, before)\n link.slug = await resolveRestoredLinkSlug(em, before)\n } else {\n link = em.create(CheckoutLink, {\n ...createLinkFromSnapshot(before),\n slug: await resolveRestoredLinkSlug(em, before),\n })\n em.persist(link)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createLinkCommand)\nregisterCommand(updateLinkCommand)\nregisterCommand(deleteLinkCommand)\n\nexport function serializeLinkRecord(record: CheckoutLink) {\n return serializeTemplateOrLink(record)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
2
2
|
import { buildCustomFieldResetMap, loadCustomFieldSnapshot } from "@open-mercato/shared/lib/commands/customFieldSnapshots";
|
|
3
3
|
import { setCustomFieldsIfAny } from "@open-mercato/shared/lib/commands/helpers";
|
|
4
|
+
import { resolveRedoSnapshot } from "@open-mercato/shared/lib/commands/redo";
|
|
4
5
|
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
5
6
|
import { enforceCommandOptimisticLock } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
|
|
6
7
|
import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
|
|
@@ -165,6 +166,45 @@ const createTemplateCommand = {
|
|
|
165
166
|
if (!template) return;
|
|
166
167
|
template.deletedAt = /* @__PURE__ */ new Date();
|
|
167
168
|
await em.flush();
|
|
169
|
+
},
|
|
170
|
+
redo: async ({ logEntry, ctx }) => {
|
|
171
|
+
const after = resolveRedoSnapshot(logEntry);
|
|
172
|
+
if (!after) throw new CrudHttpError(400, { error: "[internal] redo snapshot unavailable for checkout template create" });
|
|
173
|
+
const em = ctx.container.resolve("em");
|
|
174
|
+
const dataEngine = ctx.container.resolve("dataEngine");
|
|
175
|
+
let template = await findOneWithDecryption(
|
|
176
|
+
em,
|
|
177
|
+
CheckoutLinkTemplate,
|
|
178
|
+
{ id: after.id },
|
|
179
|
+
{},
|
|
180
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId }
|
|
181
|
+
);
|
|
182
|
+
if (template) {
|
|
183
|
+
restoreTemplateFromSnapshot(template, after);
|
|
184
|
+
template.deletedAt = null;
|
|
185
|
+
} else {
|
|
186
|
+
template = em.create(CheckoutLinkTemplate, createTemplateFromSnapshot(after));
|
|
187
|
+
em.persist(template);
|
|
188
|
+
}
|
|
189
|
+
await em.flush();
|
|
190
|
+
const reset = buildCustomFieldResetMap(after.custom, void 0);
|
|
191
|
+
if (Object.keys(reset).length) {
|
|
192
|
+
await setCustomFieldsIfAny({
|
|
193
|
+
dataEngine,
|
|
194
|
+
entityId: CHECKOUT_ENTITY_IDS.template,
|
|
195
|
+
recordId: after.id,
|
|
196
|
+
tenantId: after.tenantId,
|
|
197
|
+
organizationId: after.organizationId,
|
|
198
|
+
values: reset,
|
|
199
|
+
notify: false
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
await emitCheckoutEvent("checkout.template.created", {
|
|
203
|
+
id: template.id,
|
|
204
|
+
tenantId: after.tenantId,
|
|
205
|
+
organizationId: after.organizationId
|
|
206
|
+
}).catch(() => void 0);
|
|
207
|
+
return { id: template.id };
|
|
168
208
|
}
|
|
169
209
|
};
|
|
170
210
|
const updateTemplateCommand = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/checkout/commands/templates.ts"],
|
|
4
|
-
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate } from '../data/entities'\nimport { createTemplateSchema, updateTemplateSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n hashCheckoutPassword,\n parseCheckoutInput,\n serializeTemplateOrLink,\n toMoneyString,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n buildSelectiveLinkedCustomFieldUpdates,\n buildSelectiveLinkedLinkSnapshot,\n captureTemplateSnapshot,\n createTemplateFromSnapshot,\n extractUndoPayload,\n captureLinkSnapshot,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n restoreTemplateFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutTemplateSnapshot,\n} from './shared'\n\ntype CheckoutTemplateUndoPayload = {\n before?: CheckoutTemplateSnapshot | null\n after?: CheckoutTemplateSnapshot | null\n}\n\nasync function syncLinkedLinksWithTemplateSnapshot(params: {\n em: EntityManager\n dataEngine: DataEngine\n scope: { organizationId: string; tenantId: string }\n templateId: string\n before: CheckoutTemplateSnapshot\n after: CheckoutTemplateSnapshot\n}) {\n const { em, dataEngine, scope, templateId, before, after } = params\n const linkedLinks = await findWithDecryption(\n em,\n CheckoutLink,\n {\n templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isLocked: false,\n },\n undefined,\n scope,\n )\n\n let changedLinks = false\n\n for (const link of linkedLinks) {\n const currentLinkSnapshot = captureLinkSnapshot(link)\n const nextLinkSnapshot = buildSelectiveLinkedLinkSnapshot(currentLinkSnapshot, before, after)\n if (nextLinkSnapshot.changed) {\n restoreLinkFromSnapshot(link, nextLinkSnapshot.snapshot)\n changedLinks = true\n }\n\n const currentCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n const customFieldUpdates = buildSelectiveLinkedCustomFieldUpdates(currentCustom, before.custom, after.custom)\n if (Object.keys(customFieldUpdates).length > 0) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n values: customFieldUpdates,\n })\n }\n }\n\n if (changedLinks) {\n await em.flush()\n }\n}\n\nconst createTemplateCommand: CommandHandler<Record<string, unknown>, { id: string }> = {\n id: 'checkout.template.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n validateDescriptorCurrencies(parsed.gatewayProviderKey, deriveConfiguredCurrencies(parsed))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(parsed.gatewayProviderKey, descriptorService, scope)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = em.create(CheckoutLinkTemplate, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n ...parsed,\n fixedPriceAmount: toMoneyString(parsed.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(parsed.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(parsed.customAmountMin),\n customAmountMax: toMoneyString(parsed.customAmountMax),\n passwordHash: await hashCheckoutPassword(parsed.password),\n } as any)\n em.persist(template)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.template.created', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { id: template.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, { id: result.id })\n if (!template) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return captureTemplateSnapshot(template, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.create', 'Create pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const template = await em.findOne(CheckoutLinkTemplate, { id: after.id })\n if (!template) return\n template.deletedAt = new Date()\n await em.flush()\n },\n}\n\nconst updateTemplateCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.template.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return { before: captureTemplateSnapshot(template, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n validateDescriptorCurrencies(parsed.gatewayProviderKey ?? null, deriveConfiguredCurrencies(parsed))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(parsed.gatewayProviderKey ?? null, descriptorService, scope)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.template',\n resourceId: template.id,\n current: template.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const beforeCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n const beforeSnapshot = captureTemplateSnapshot(template, beforeCustom)\n const passwordHash = parsed.password !== undefined\n ? await hashCheckoutPassword(parsed.password)\n : template.passwordHash\n Object.assign(template, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : template.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : template.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : template.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : template.customAmountMax,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n const afterCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n const afterSnapshot = captureTemplateSnapshot(template, afterCustom)\n await syncLinkedLinksWithTemplateSnapshot({\n em,\n dataEngine,\n scope,\n templateId: template.id,\n before: beforeSnapshot,\n after: afterSnapshot,\n })\n await emitCheckoutEvent('checkout.template.updated', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n captureAfter: async (input, _result, ctx) => {\n const { parsed } = parseCheckoutInput(input, updateTemplateSchema.parse)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, { id: parsed.id, deletedAt: null })\n if (!template) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return captureTemplateSnapshot(template, custom)\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutTemplateSnapshot | null | undefined\n const after = snapshots.after as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.update', 'Update pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: after?.id ?? before?.id ?? readCommandId(input, 'Template id is required'),\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = await em.findOne(CheckoutLinkTemplate, { id: before.id, deletedAt: null })\n if (!template) return\n restoreTemplateFromSnapshot(template, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n if (after) {\n await syncLinkedLinksWithTemplateSnapshot({\n em,\n dataEngine,\n scope: { organizationId: before.organizationId, tenantId: before.tenantId },\n templateId: before.id,\n before: after,\n after: before,\n })\n }\n },\n}\n\nconst deleteTemplateCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.template.delete',\n async prepare(rawInput, ctx) {\n const templateId = readCommandId(rawInput, 'Template id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return { before: captureTemplateSnapshot(template, custom) }\n },\n async execute(rawInput, ctx) {\n const templateId = readCommandId(rawInput, 'Template id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.template',\n resourceId: template.id,\n current: template.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n template.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.template.deleted', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.delete', 'Delete pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: before?.id ?? readCommandId(input, 'Template id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let template = await em.findOne(CheckoutLinkTemplate, { id: before.id })\n if (template) {\n restoreTemplateFromSnapshot(template, before)\n } else {\n template = em.create(CheckoutLinkTemplate, createTemplateFromSnapshot(before))\n em.persist(template)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createTemplateCommand)\nregisterCommand(updateTemplateCommand)\nregisterCommand(deleteTemplateCommand)\n\nexport function serializeTemplateRecord(record: CheckoutLinkTemplate) {\n return serializeTemplateOrLink(record)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'\nimport { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CheckoutLink, CheckoutLinkTemplate } from '../data/entities'\nimport { createTemplateSchema, updateTemplateSchema } from '../data/validators'\nimport { CHECKOUT_ENTITY_IDS } from '../lib/constants'\nimport {\n ensureGatewayProviderConfigured,\n type PaymentGatewayDescriptorService,\n} from '../lib/gatewayProviderAvailability'\nimport { emitCheckoutEvent } from '../events'\nimport {\n deriveConfiguredCurrencies,\n hashCheckoutPassword,\n parseCheckoutInput,\n serializeTemplateOrLink,\n toMoneyString,\n validateDescriptorCurrencies,\n} from '../lib/utils'\nimport {\n buildSelectiveLinkedCustomFieldUpdates,\n buildSelectiveLinkedLinkSnapshot,\n captureTemplateSnapshot,\n createTemplateFromSnapshot,\n extractUndoPayload,\n captureLinkSnapshot,\n readCommandId,\n resolveCommandScope,\n restoreLinkFromSnapshot,\n restoreTemplateFromSnapshot,\n toCheckoutAuditSnapshot,\n type CheckoutTemplateSnapshot,\n} from './shared'\n\ntype CheckoutTemplateUndoPayload = {\n before?: CheckoutTemplateSnapshot | null\n after?: CheckoutTemplateSnapshot | null\n}\n\nasync function syncLinkedLinksWithTemplateSnapshot(params: {\n em: EntityManager\n dataEngine: DataEngine\n scope: { organizationId: string; tenantId: string }\n templateId: string\n before: CheckoutTemplateSnapshot\n after: CheckoutTemplateSnapshot\n}) {\n const { em, dataEngine, scope, templateId, before, after } = params\n const linkedLinks = await findWithDecryption(\n em,\n CheckoutLink,\n {\n templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n isLocked: false,\n },\n undefined,\n scope,\n )\n\n let changedLinks = false\n\n for (const link of linkedLinks) {\n const currentLinkSnapshot = captureLinkSnapshot(link)\n const nextLinkSnapshot = buildSelectiveLinkedLinkSnapshot(currentLinkSnapshot, before, after)\n if (nextLinkSnapshot.changed) {\n restoreLinkFromSnapshot(link, nextLinkSnapshot.snapshot)\n changedLinks = true\n }\n\n const currentCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n })\n const customFieldUpdates = buildSelectiveLinkedCustomFieldUpdates(currentCustom, before.custom, after.custom)\n if (Object.keys(customFieldUpdates).length > 0) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.link,\n recordId: link.id,\n tenantId: link.tenantId,\n organizationId: link.organizationId,\n values: customFieldUpdates,\n })\n }\n }\n\n if (changedLinks) {\n await em.flush()\n }\n}\n\nconst createTemplateCommand: CommandHandler<Record<string, unknown>, { id: string }> = {\n id: 'checkout.template.create',\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, createTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n validateDescriptorCurrencies(parsed.gatewayProviderKey, deriveConfiguredCurrencies(parsed))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(parsed.gatewayProviderKey, descriptorService, scope)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = em.create(CheckoutLinkTemplate, {\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n ...parsed,\n fixedPriceAmount: toMoneyString(parsed.fixedPriceAmount),\n fixedPriceOriginalAmount: toMoneyString(parsed.fixedPriceOriginalAmount),\n customAmountMin: toMoneyString(parsed.customAmountMin),\n customAmountMax: toMoneyString(parsed.customAmountMax),\n passwordHash: await hashCheckoutPassword(parsed.password),\n } as any)\n em.persist(template)\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n await emitCheckoutEvent('checkout.template.created', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { id: template.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, { id: result.id })\n if (!template) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return captureTemplateSnapshot(template, custom)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const after = snapshots.after as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.create', 'Create pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: result.id,\n tenantId: after?.tenantId ?? null,\n organizationId: after?.organizationId ?? null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n after: after ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)?.after\n if (!after) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const reset = buildCustomFieldResetMap(undefined, after.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n const template = await em.findOne(CheckoutLinkTemplate, { id: after.id })\n if (!template) return\n template.deletedAt = new Date()\n await em.flush()\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<CheckoutTemplateSnapshot>(logEntry)\n if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout template create' })\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let template = await findOneWithDecryption(\n em,\n CheckoutLinkTemplate,\n { id: after.id },\n {},\n { tenantId: after.tenantId, organizationId: after.organizationId },\n )\n if (template) {\n restoreTemplateFromSnapshot(template, after)\n template.deletedAt = null\n } else {\n template = em.create(CheckoutLinkTemplate, createTemplateFromSnapshot(after))\n em.persist(template)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(after.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: after.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n values: reset,\n notify: false,\n })\n }\n await emitCheckoutEvent('checkout.template.created', {\n id: template.id,\n tenantId: after.tenantId,\n organizationId: after.organizationId,\n }).catch(() => undefined)\n return { id: template.id }\n },\n}\n\nconst updateTemplateCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.template.update',\n async prepare(rawInput, ctx) {\n const { parsed } = parseCheckoutInput(rawInput, updateTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return { before: captureTemplateSnapshot(template, custom) }\n },\n async execute(rawInput, ctx) {\n const { parsed, customFields } = parseCheckoutInput(rawInput, updateTemplateSchema.parse)\n const scope = resolveCommandScope(ctx)\n validateDescriptorCurrencies(parsed.gatewayProviderKey ?? null, deriveConfiguredCurrencies(parsed))\n const descriptorService = ctx.container.resolve('paymentGatewayDescriptorService') as PaymentGatewayDescriptorService\n await ensureGatewayProviderConfigured(parsed.gatewayProviderKey ?? null, descriptorService, scope)\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: parsed.id,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.template',\n resourceId: template.id,\n current: template.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n const beforeCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n const beforeSnapshot = captureTemplateSnapshot(template, beforeCustom)\n const passwordHash = parsed.password !== undefined\n ? await hashCheckoutPassword(parsed.password)\n : template.passwordHash\n Object.assign(template, {\n ...parsed,\n fixedPriceAmount: parsed.fixedPriceAmount !== undefined ? toMoneyString(parsed.fixedPriceAmount) : template.fixedPriceAmount,\n fixedPriceOriginalAmount: parsed.fixedPriceOriginalAmount !== undefined ? toMoneyString(parsed.fixedPriceOriginalAmount) : template.fixedPriceOriginalAmount,\n customAmountMin: parsed.customAmountMin !== undefined ? toMoneyString(parsed.customAmountMin) : template.customAmountMin,\n customAmountMax: parsed.customAmountMax !== undefined ? toMoneyString(parsed.customAmountMax) : template.customAmountMax,\n passwordHash,\n })\n await em.flush()\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n values: customFields,\n })\n const afterCustom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n const afterSnapshot = captureTemplateSnapshot(template, afterCustom)\n await syncLinkedLinksWithTemplateSnapshot({\n em,\n dataEngine,\n scope,\n templateId: template.id,\n before: beforeSnapshot,\n after: afterSnapshot,\n })\n await emitCheckoutEvent('checkout.template.updated', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n captureAfter: async (input, _result, ctx) => {\n const { parsed } = parseCheckoutInput(input, updateTemplateSchema.parse)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, { id: parsed.id, deletedAt: null })\n if (!template) return null\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return captureTemplateSnapshot(template, custom)\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutTemplateSnapshot | null | undefined\n const after = snapshots.after as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.update', 'Update pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: after?.id ?? before?.id ?? readCommandId(input, 'Template id is required'),\n tenantId: after?.tenantId ?? before?.tenantId ?? null,\n organizationId: after?.organizationId ?? before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n snapshotAfter: after ? toCheckoutAuditSnapshot(after) : null,\n payload: {\n undo: {\n before: before ?? null,\n after: after ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const undo = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)\n const before = undo?.before\n const after = undo?.after\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n const template = await em.findOne(CheckoutLinkTemplate, { id: before.id, deletedAt: null })\n if (!template) return\n restoreTemplateFromSnapshot(template, before)\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, after?.custom)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n if (after) {\n await syncLinkedLinksWithTemplateSnapshot({\n em,\n dataEngine,\n scope: { organizationId: before.organizationId, tenantId: before.tenantId },\n templateId: before.id,\n before: after,\n after: before,\n })\n }\n },\n}\n\nconst deleteTemplateCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {\n id: 'checkout.template.delete',\n async prepare(rawInput, ctx) {\n const templateId = readCommandId(rawInput, 'Template id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) return {}\n const custom = await loadCustomFieldSnapshot(em, {\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: template.id,\n tenantId: template.tenantId,\n organizationId: template.organizationId,\n })\n return { before: captureTemplateSnapshot(template, custom) }\n },\n async execute(rawInput, ctx) {\n const templateId = readCommandId(rawInput, 'Template id is required')\n const scope = resolveCommandScope(ctx)\n const em = ctx.container.resolve('em') as EntityManager\n const template = await findOneWithDecryption(em, CheckoutLinkTemplate, {\n id: templateId,\n organizationId: scope.organizationId,\n tenantId: scope.tenantId,\n deletedAt: null,\n }, undefined, scope)\n if (!template) throw new CrudHttpError(404, { error: 'Template not found' })\n enforceCommandOptimisticLock({\n resourceKind: 'checkout.template',\n resourceId: template.id,\n current: template.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n template.deletedAt = new Date()\n await em.flush()\n await emitCheckoutEvent('checkout.template.deleted', {\n id: template.id,\n tenantId: scope.tenantId,\n organizationId: scope.organizationId,\n }).catch(() => undefined)\n return { ok: true }\n },\n buildLog: async ({ snapshots, input }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as CheckoutTemplateSnapshot | null | undefined\n return {\n actionLabel: translate('checkout.audit.templates.delete', 'Delete pay-link template'),\n resourceKind: 'checkout.template',\n resourceId: before?.id ?? readCommandId(input, 'Template id is required'),\n tenantId: before?.tenantId ?? null,\n organizationId: before?.organizationId ?? null,\n snapshotBefore: before ? toCheckoutAuditSnapshot(before) : null,\n payload: {\n undo: {\n before: before ?? null,\n } satisfies CheckoutTemplateUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<CheckoutTemplateUndoPayload>(logEntry)?.before\n if (!before) return\n const em = ctx.container.resolve('em') as EntityManager\n const dataEngine = ctx.container.resolve('dataEngine') as DataEngine\n let template = await em.findOne(CheckoutLinkTemplate, { id: before.id })\n if (template) {\n restoreTemplateFromSnapshot(template, before)\n } else {\n template = em.create(CheckoutLinkTemplate, createTemplateFromSnapshot(before))\n em.persist(template)\n }\n await em.flush()\n const reset = buildCustomFieldResetMap(before.custom, undefined)\n if (Object.keys(reset).length) {\n await setCustomFieldsIfAny({\n dataEngine,\n entityId: CHECKOUT_ENTITY_IDS.template,\n recordId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n values: reset,\n notify: false,\n })\n }\n },\n}\n\nregisterCommand(createTemplateCommand)\nregisterCommand(updateTemplateCommand)\nregisterCommand(deleteTemplateCommand)\n\nexport function serializeTemplateRecord(record: CheckoutLinkTemplate) {\n return serializeTemplateOrLink(record)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/jest.config.cjs
CHANGED
|
@@ -9,6 +9,8 @@ module.exports = {
|
|
|
9
9
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
|
10
10
|
moduleNameMapper: {
|
|
11
11
|
'^@open-mercato/checkout/(.*)$': '<rootDir>/src/$1',
|
|
12
|
+
'^@open-mercato/cache$': '<rootDir>/../cache/src/index.ts',
|
|
13
|
+
'^@open-mercato/cache/(.*)$': '<rootDir>/../cache/src/$1',
|
|
12
14
|
'^@open-mercato/core/(.*)$': '<rootDir>/../core/src/$1',
|
|
13
15
|
'^@open-mercato/shared/(.*)$': '<rootDir>/../shared/src/$1',
|
|
14
16
|
'^@open-mercato/queue/(.*)$': '<rootDir>/../queue/src/$1',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/checkout",
|
|
3
|
-
"version": "0.6.5-develop.
|
|
3
|
+
"version": "0.6.5-develop.4732.1.732f6c67a5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -61,18 +61,18 @@
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@open-mercato/core": "0.6.5-develop.
|
|
65
|
-
"@open-mercato/ui": "0.6.5-develop.
|
|
64
|
+
"@open-mercato/core": "0.6.5-develop.4732.1.732f6c67a5",
|
|
65
|
+
"@open-mercato/ui": "0.6.5-develop.4732.1.732f6c67a5",
|
|
66
66
|
"bcryptjs": "^3.0.3"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@mikro-orm/postgresql": "^7.0.14",
|
|
70
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
70
|
+
"@open-mercato/shared": "0.6.5-develop.4732.1.732f6c67a5",
|
|
71
71
|
"react": "^19.0.0",
|
|
72
72
|
"react-dom": "^19.0.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|
|
75
|
-
"@open-mercato/shared": "0.6.5-develop.
|
|
75
|
+
"@open-mercato/shared": "0.6.5-develop.4732.1.732f6c67a5",
|
|
76
76
|
"@types/jest": "^30.0.0",
|
|
77
77
|
"@types/react": "^19.2.16",
|
|
78
78
|
"@types/react-dom": "^19.2.3",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { commandRegistry } from '@open-mercato/shared/lib/commands/registry'
|
|
2
|
+
import '../index'
|
|
3
|
+
|
|
4
|
+
describe('checkout undoable create command redo coverage', () => {
|
|
5
|
+
it('requires every logged undoable *.create command to define redo', () => {
|
|
6
|
+
const missingRedo = commandRegistry
|
|
7
|
+
.list()
|
|
8
|
+
.sort()
|
|
9
|
+
.filter((id) => id.startsWith('checkout.') && id.endsWith('.create'))
|
|
10
|
+
.filter((id) => {
|
|
11
|
+
const handler = commandRegistry.get(id)
|
|
12
|
+
return Boolean(
|
|
13
|
+
handler?.isUndoable &&
|
|
14
|
+
typeof handler.buildLog === 'function' &&
|
|
15
|
+
typeof handler.redo !== 'function',
|
|
16
|
+
)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
expect(missingRedo).toEqual([])
|
|
20
|
+
})
|
|
21
|
+
})
|
|
@@ -4,6 +4,7 @@ import type { CommandHandler } from '@open-mercato/shared/lib/commands'
|
|
|
4
4
|
import { registerCommand } from '@open-mercato/shared/lib/commands'
|
|
5
5
|
import { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'
|
|
6
6
|
import { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'
|
|
7
|
+
import { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'
|
|
7
8
|
import { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'
|
|
8
9
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
9
10
|
import { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
@@ -200,6 +201,59 @@ const createLinkCommand: CommandHandler<Record<string, unknown>, { id: string; s
|
|
|
200
201
|
link.deletedAt = new Date()
|
|
201
202
|
await em.flush()
|
|
202
203
|
},
|
|
204
|
+
redo: async ({ logEntry, ctx }) => {
|
|
205
|
+
const after = resolveRedoSnapshot<CheckoutLinkSnapshot>(logEntry)
|
|
206
|
+
if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout link create' })
|
|
207
|
+
const em = ctx.container.resolve('em') as EntityManager
|
|
208
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
209
|
+
let link = await findOneWithDecryption(
|
|
210
|
+
em,
|
|
211
|
+
CheckoutLink,
|
|
212
|
+
{ id: after.id },
|
|
213
|
+
{},
|
|
214
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId },
|
|
215
|
+
)
|
|
216
|
+
if (link) {
|
|
217
|
+
restoreLinkFromSnapshot(link, after)
|
|
218
|
+
link.deletedAt = null
|
|
219
|
+
link.slug = await resolveRestoredLinkSlug(em, after)
|
|
220
|
+
} else {
|
|
221
|
+
link = em.create(CheckoutLink, {
|
|
222
|
+
...createLinkFromSnapshot(after),
|
|
223
|
+
slug: await resolveRestoredLinkSlug(em, after),
|
|
224
|
+
})
|
|
225
|
+
em.persist(link)
|
|
226
|
+
}
|
|
227
|
+
await em.flush()
|
|
228
|
+
const reset = buildCustomFieldResetMap(after.custom, undefined)
|
|
229
|
+
if (Object.keys(reset).length) {
|
|
230
|
+
await setCustomFieldsIfAny({
|
|
231
|
+
dataEngine,
|
|
232
|
+
entityId: CHECKOUT_ENTITY_IDS.link,
|
|
233
|
+
recordId: after.id,
|
|
234
|
+
tenantId: after.tenantId,
|
|
235
|
+
organizationId: after.organizationId,
|
|
236
|
+
values: reset,
|
|
237
|
+
notify: false,
|
|
238
|
+
})
|
|
239
|
+
}
|
|
240
|
+
await emitCheckoutEvent('checkout.link.created', {
|
|
241
|
+
id: link.id,
|
|
242
|
+
slug: link.slug,
|
|
243
|
+
status: link.status,
|
|
244
|
+
tenantId: after.tenantId,
|
|
245
|
+
organizationId: after.organizationId,
|
|
246
|
+
}).catch(() => undefined)
|
|
247
|
+
if (link.status === 'active') {
|
|
248
|
+
await emitCheckoutEvent('checkout.link.published', {
|
|
249
|
+
id: link.id,
|
|
250
|
+
slug: link.slug,
|
|
251
|
+
tenantId: after.tenantId,
|
|
252
|
+
organizationId: after.organizationId,
|
|
253
|
+
}).catch(() => undefined)
|
|
254
|
+
}
|
|
255
|
+
return { id: link.id, slug: link.slug }
|
|
256
|
+
},
|
|
203
257
|
}
|
|
204
258
|
|
|
205
259
|
const updateLinkCommand: CommandHandler<Record<string, unknown>, { ok: true; slug: string }> = {
|
|
@@ -4,6 +4,7 @@ import type { CommandHandler } from '@open-mercato/shared/lib/commands'
|
|
|
4
4
|
import { registerCommand } from '@open-mercato/shared/lib/commands'
|
|
5
5
|
import { buildCustomFieldResetMap, loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'
|
|
6
6
|
import { setCustomFieldsIfAny } from '@open-mercato/shared/lib/commands/helpers'
|
|
7
|
+
import { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'
|
|
7
8
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
8
9
|
import { enforceCommandOptimisticLock } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
9
10
|
import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
@@ -189,6 +190,45 @@ const createTemplateCommand: CommandHandler<Record<string, unknown>, { id: strin
|
|
|
189
190
|
template.deletedAt = new Date()
|
|
190
191
|
await em.flush()
|
|
191
192
|
},
|
|
193
|
+
redo: async ({ logEntry, ctx }) => {
|
|
194
|
+
const after = resolveRedoSnapshot<CheckoutTemplateSnapshot>(logEntry)
|
|
195
|
+
if (!after) throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for checkout template create' })
|
|
196
|
+
const em = ctx.container.resolve('em') as EntityManager
|
|
197
|
+
const dataEngine = ctx.container.resolve('dataEngine') as DataEngine
|
|
198
|
+
let template = await findOneWithDecryption(
|
|
199
|
+
em,
|
|
200
|
+
CheckoutLinkTemplate,
|
|
201
|
+
{ id: after.id },
|
|
202
|
+
{},
|
|
203
|
+
{ tenantId: after.tenantId, organizationId: after.organizationId },
|
|
204
|
+
)
|
|
205
|
+
if (template) {
|
|
206
|
+
restoreTemplateFromSnapshot(template, after)
|
|
207
|
+
template.deletedAt = null
|
|
208
|
+
} else {
|
|
209
|
+
template = em.create(CheckoutLinkTemplate, createTemplateFromSnapshot(after))
|
|
210
|
+
em.persist(template)
|
|
211
|
+
}
|
|
212
|
+
await em.flush()
|
|
213
|
+
const reset = buildCustomFieldResetMap(after.custom, undefined)
|
|
214
|
+
if (Object.keys(reset).length) {
|
|
215
|
+
await setCustomFieldsIfAny({
|
|
216
|
+
dataEngine,
|
|
217
|
+
entityId: CHECKOUT_ENTITY_IDS.template,
|
|
218
|
+
recordId: after.id,
|
|
219
|
+
tenantId: after.tenantId,
|
|
220
|
+
organizationId: after.organizationId,
|
|
221
|
+
values: reset,
|
|
222
|
+
notify: false,
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
await emitCheckoutEvent('checkout.template.created', {
|
|
226
|
+
id: template.id,
|
|
227
|
+
tenantId: after.tenantId,
|
|
228
|
+
organizationId: after.organizationId,
|
|
229
|
+
}).catch(() => undefined)
|
|
230
|
+
return { id: template.id }
|
|
231
|
+
},
|
|
192
232
|
}
|
|
193
233
|
|
|
194
234
|
const updateTemplateCommand: CommandHandler<Record<string, unknown>, { ok: true }> = {
|