@open-mercato/checkout 0.6.4-develop.4371.1.8f3030407e → 0.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/checkout/__integration__/TC-CHK-CRUDFORM-001.spec.js +125 -0
  3. package/dist/modules/checkout/__integration__/TC-CHK-CRUDFORM-001.spec.js.map +7 -0
  4. package/dist/modules/checkout/__integration__/TC-CHK-CRUDFORM-002.spec.js +139 -0
  5. package/dist/modules/checkout/__integration__/TC-CHK-CRUDFORM-002.spec.js.map +7 -0
  6. package/dist/modules/checkout/__integration__/TC-CHKT-008.spec.js +2 -0
  7. package/dist/modules/checkout/__integration__/TC-CHKT-008.spec.js.map +2 -2
  8. package/dist/modules/checkout/__integration__/TC-CHKT-039-null-gateway-edit.spec.js +115 -0
  9. package/dist/modules/checkout/__integration__/TC-CHKT-039-null-gateway-edit.spec.js.map +7 -0
  10. package/dist/modules/checkout/__integration__/TC-CHKT-039-stale-delete-lock.spec.js +66 -0
  11. package/dist/modules/checkout/__integration__/TC-CHKT-039-stale-delete-lock.spec.js.map +7 -0
  12. package/dist/modules/checkout/__integration__/TC-CHKT-040-gateway-settings-select.spec.js +52 -0
  13. package/dist/modules/checkout/__integration__/TC-CHKT-040-gateway-settings-select.spec.js.map +7 -0
  14. package/dist/modules/checkout/__integration__/TC-CHKT-041-template-stale-delete-conflict.spec.js +44 -0
  15. package/dist/modules/checkout/__integration__/TC-CHKT-041-template-stale-delete-conflict.spec.js.map +7 -0
  16. package/dist/modules/checkout/backend/checkout/pay-links/page.js +9 -0
  17. package/dist/modules/checkout/backend/checkout/pay-links/page.js.map +2 -2
  18. package/dist/modules/checkout/backend/checkout/templates/page.js +9 -0
  19. package/dist/modules/checkout/backend/checkout/templates/page.js.map +2 -2
  20. package/dist/modules/checkout/commands/links.js +67 -0
  21. package/dist/modules/checkout/commands/links.js.map +2 -2
  22. package/dist/modules/checkout/commands/templates.js +69 -2
  23. package/dist/modules/checkout/commands/templates.js.map +2 -2
  24. package/dist/modules/checkout/components/GatewaySettingsFields.js +32 -15
  25. package/dist/modules/checkout/components/GatewaySettingsFields.js.map +2 -2
  26. package/dist/modules/checkout/components/LinkTemplateForm.js +27 -7
  27. package/dist/modules/checkout/components/LinkTemplateForm.js.map +2 -2
  28. package/dist/modules/checkout/data/validators.js +18 -2
  29. package/dist/modules/checkout/data/validators.js.map +2 -2
  30. package/dist/modules/checkout/lib/utils.js +26 -5
  31. package/dist/modules/checkout/lib/utils.js.map +2 -2
  32. package/jest.config.cjs +2 -0
  33. package/package.json +7 -8
  34. package/src/modules/checkout/__integration__/TC-CHK-CRUDFORM-001.spec.ts +158 -0
  35. package/src/modules/checkout/__integration__/TC-CHK-CRUDFORM-002.spec.ts +171 -0
  36. package/src/modules/checkout/__integration__/TC-CHKT-008.spec.ts +4 -0
  37. package/src/modules/checkout/__integration__/TC-CHKT-039-null-gateway-edit.spec.ts +131 -0
  38. package/src/modules/checkout/__integration__/TC-CHKT-039-stale-delete-lock.spec.ts +98 -0
  39. package/src/modules/checkout/__integration__/TC-CHKT-040-gateway-settings-select.spec.ts +60 -0
  40. package/src/modules/checkout/__integration__/TC-CHKT-041-template-stale-delete-conflict.spec.ts +58 -0
  41. package/src/modules/checkout/backend/checkout/pay-links/page.tsx +8 -0
  42. package/src/modules/checkout/backend/checkout/templates/page.tsx +8 -0
  43. package/src/modules/checkout/commands/__tests__/optimistic-lock.test.ts +261 -0
  44. package/src/modules/checkout/commands/__tests__/redo-coverage.test.ts +21 -0
  45. package/src/modules/checkout/commands/links.ts +67 -0
  46. package/src/modules/checkout/commands/templates.ts +74 -2
  47. package/src/modules/checkout/components/GatewaySettingsFields.tsx +40 -18
  48. package/src/modules/checkout/components/LinkTemplateForm.tsx +27 -7
  49. package/src/modules/checkout/data/__tests__/validators.test.ts +66 -1
  50. package/src/modules/checkout/data/validators.ts +18 -2
  51. package/src/modules/checkout/lib/__tests__/utils.test.ts +112 -0
  52. package/src/modules/checkout/lib/utils.ts +41 -5
@@ -1,7 +1,9 @@
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";
6
+ import { enforceCommandOptimisticLock, enforceRecordGoneIsConflict } from "@open-mercato/shared/lib/crud/optimistic-lock-command";
5
7
  import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
6
8
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
7
9
  import { CheckoutLink, CheckoutLinkTemplate } from "../data/entities.js";
@@ -164,6 +166,45 @@ const createTemplateCommand = {
164
166
  if (!template) return;
165
167
  template.deletedAt = /* @__PURE__ */ new Date();
166
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 };
167
208
  }
168
209
  };
169
210
  const updateTemplateCommand = {
@@ -201,7 +242,20 @@ const updateTemplateCommand = {
201
242
  tenantId: scope.tenantId,
202
243
  deletedAt: null
203
244
  }, void 0, scope);
204
- if (!template) throw new CrudHttpError(404, { error: "Template not found" });
245
+ if (!template) {
246
+ enforceRecordGoneIsConflict({
247
+ resourceKind: "checkout.template",
248
+ resourceId: parsed.id,
249
+ request: ctx.request ?? null
250
+ });
251
+ throw new CrudHttpError(404, { error: "Template not found" });
252
+ }
253
+ enforceCommandOptimisticLock({
254
+ resourceKind: "checkout.template",
255
+ resourceId: template.id,
256
+ current: template.updatedAt ?? null,
257
+ request: ctx.request ?? null
258
+ });
205
259
  const beforeCustom = await loadCustomFieldSnapshot(em, {
206
260
  entityId: CHECKOUT_ENTITY_IDS.template,
207
261
  recordId: template.id,
@@ -348,7 +402,20 @@ const deleteTemplateCommand = {
348
402
  tenantId: scope.tenantId,
349
403
  deletedAt: null
350
404
  }, void 0, scope);
351
- if (!template) throw new CrudHttpError(404, { error: "Template not found" });
405
+ if (!template) {
406
+ enforceRecordGoneIsConflict({
407
+ resourceKind: "checkout.template",
408
+ resourceId: templateId,
409
+ request: ctx.request ?? null
410
+ });
411
+ throw new CrudHttpError(404, { error: "Template not found" });
412
+ }
413
+ enforceCommandOptimisticLock({
414
+ resourceKind: "checkout.template",
415
+ resourceId: template.id,
416
+ current: template.updatedAt ?? null,
417
+ request: ctx.request ?? null
418
+ });
352
419
  template.deletedAt = /* @__PURE__ */ new Date();
353
420
  await em.flush();
354
421
  await emitCheckoutEvent("checkout.template.deleted", {
@@ -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 { 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 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 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, enforceRecordGoneIsConflict } 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) {\n // The template was deleted in another tab. When the client opted into\n // optimistic locking, surface the unified conflict bar instead of a bare\n // 404 (#2529); otherwise the plain 404 still fires for API consumers.\n enforceRecordGoneIsConflict({\n resourceKind: 'checkout.template',\n resourceId: parsed.id,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Template not found' })\n }\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) {\n // Already deleted elsewhere \u2014 convert to a 409 conflict when the client\n // sent the optimistic-lock header so the stale edit surfaces cleanly (#2529).\n enforceRecordGoneIsConflict({\n resourceKind: 'checkout.template',\n resourceId: templateId,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Template not found' })\n }\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
  }
@@ -7,16 +7,36 @@ import { Input } from "@open-mercato/ui/primitives/input";
7
7
  import { Label } from "@open-mercato/ui/primitives/label";
8
8
  import { Alert, AlertDescription } from "@open-mercato/ui/primitives/alert";
9
9
  import { Textarea } from "@open-mercato/ui/primitives/textarea";
10
+ import { Checkbox } from "@open-mercato/ui/primitives/checkbox";
11
+ import {
12
+ Select,
13
+ SelectContent,
14
+ SelectItem,
15
+ SelectTrigger,
16
+ SelectValue
17
+ } from "@open-mercato/ui/primitives/select";
10
18
  function GatewaySettingsFields({ providerKey, value, onChange }) {
11
19
  const t = useT();
12
20
  const [descriptor, setDescriptor] = React.useState(null);
21
+ const patchSetting = React.useCallback(
22
+ (fieldKey, nextValue) => {
23
+ const next = { ...value ?? {} };
24
+ if (nextValue === void 0 || nextValue === null || nextValue === "") {
25
+ delete next[fieldKey];
26
+ } else {
27
+ next[fieldKey] = nextValue;
28
+ }
29
+ onChange(next);
30
+ },
31
+ [onChange, value]
32
+ );
13
33
  const toggleMultiselectValue = React.useCallback(
14
34
  (fieldKey, optionValue) => {
15
35
  const current = Array.isArray(value?.[fieldKey]) ? value?.[fieldKey].filter((entry) => typeof entry === "string") : [];
16
36
  const next = current.includes(optionValue) ? current.filter((entry) => entry !== optionValue) : [...current, optionValue];
17
- onChange({ ...value ?? {}, [fieldKey]: next });
37
+ patchSetting(fieldKey, next.length ? next : void 0);
18
38
  },
19
- [onChange, value]
39
+ [patchSetting, value]
20
40
  );
21
41
  React.useEffect(() => {
22
42
  let active = true;
@@ -47,14 +67,13 @@ function GatewaySettingsFields({ providerKey, value, onChange }) {
47
67
  return /* @__PURE__ */ jsxs("div", { className: "space-y-2 rounded-lg border border-border/70 bg-muted/30 p-3", children: [
48
68
  /* @__PURE__ */ jsx(Label, { children: field.label }),
49
69
  field.type === "select" ? /* @__PURE__ */ jsxs(
50
- "select",
70
+ Select,
51
71
  {
52
- className: "w-full rounded-md border bg-background px-3 py-2 text-sm",
53
72
  value: typeof currentValue === "string" ? currentValue : "",
54
- onChange: (event) => onChange({ ...value ?? {}, [field.key]: event.target.value }),
73
+ onValueChange: (next) => patchSetting(field.key, next),
55
74
  children: [
56
- /* @__PURE__ */ jsx("option", { value: "", children: t("checkout.gatewaySettings.selectPlaceholder") }),
57
- (field.options ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option.value, children: option.label }, option.value))
75
+ /* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("checkout.gatewaySettings.selectPlaceholder") }) }),
76
+ /* @__PURE__ */ jsx(SelectContent, { children: (field.options ?? []).map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: option.label }, option.value)) })
58
77
  ]
59
78
  }
60
79
  ) : field.type === "multiselect" ? /* @__PURE__ */ jsx("div", { className: "grid gap-2 sm:grid-cols-2", children: (field.options ?? []).map((option) => {
@@ -66,11 +85,10 @@ function GatewaySettingsFields({ providerKey, value, onChange }) {
66
85
  className: "flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm",
67
86
  children: [
68
87
  /* @__PURE__ */ jsx(
69
- "input",
88
+ Checkbox,
70
89
  {
71
- type: "checkbox",
72
90
  checked,
73
- onChange: () => toggleMultiselectValue(field.key, option.value)
91
+ onCheckedChange: () => toggleMultiselectValue(field.key, option.value)
74
92
  }
75
93
  ),
76
94
  /* @__PURE__ */ jsx("span", { children: option.label })
@@ -80,11 +98,10 @@ function GatewaySettingsFields({ providerKey, value, onChange }) {
80
98
  );
81
99
  }) }) : field.type === "boolean" ? /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
82
100
  /* @__PURE__ */ jsx(
83
- "input",
101
+ Checkbox,
84
102
  {
85
- type: "checkbox",
86
103
  checked: currentValue === true,
87
- onChange: (event) => onChange({ ...value ?? {}, [field.key]: event.target.checked })
104
+ onCheckedChange: (next) => patchSetting(field.key, next === true)
88
105
  }
89
106
  ),
90
107
  t("checkout.common.enabled")
@@ -92,14 +109,14 @@ function GatewaySettingsFields({ providerKey, value, onChange }) {
92
109
  Textarea,
93
110
  {
94
111
  value: typeof currentValue === "string" ? currentValue : "",
95
- onChange: (event) => onChange({ ...value ?? {}, [field.key]: event.target.value })
112
+ onChange: (event) => patchSetting(field.key, event.target.value)
96
113
  }
97
114
  ) : /* @__PURE__ */ jsx(
98
115
  Input,
99
116
  {
100
117
  type: field.type === "number" ? "number" : field.type === "secret" ? "password" : "text",
101
118
  value: typeof currentValue === "string" || typeof currentValue === "number" ? `${currentValue}` : "",
102
- onChange: (event) => onChange({ ...value ?? {}, [field.key]: event.target.value })
119
+ onChange: (event) => patchSetting(field.key, event.target.value)
103
120
  }
104
121
  ),
105
122
  field.description ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: field.description }) : null
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/checkout/components/GatewaySettingsFields.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\n\ntype Descriptor = {\n providerKey: string\n label: string\n sessionConfig?: {\n fields?: Array<{\n key: string\n label: string\n type: 'text' | 'number' | 'select' | 'multiselect' | 'boolean' | 'textarea' | 'secret' | 'url'\n description?: string\n options?: Array<{ value: string; label: string }>\n }>\n }\n}\n\ntype Props = {\n providerKey: string | null | undefined\n value: Record<string, unknown> | null | undefined\n onChange: (next: Record<string, unknown>) => void\n}\n\nexport function GatewaySettingsFields({ providerKey, value, onChange }: Props) {\n const t = useT()\n const [descriptor, setDescriptor] = React.useState<Descriptor | null>(null)\n\n const toggleMultiselectValue = React.useCallback(\n (fieldKey: string, optionValue: string) => {\n const current = Array.isArray(value?.[fieldKey])\n ? value?.[fieldKey].filter((entry): entry is string => typeof entry === 'string')\n : []\n const next = current.includes(optionValue)\n ? current.filter((entry) => entry !== optionValue)\n : [...current, optionValue]\n onChange({ ...(value ?? {}), [fieldKey]: next })\n },\n [onChange, value],\n )\n\n React.useEffect(() => {\n let active = true\n if (!providerKey) {\n setDescriptor(null)\n return () => { active = false }\n }\n void readApiResultOrThrow<Descriptor>(`/api/payment_gateways/providers/${encodeURIComponent(providerKey)}`)\n .then((result) => {\n if (active) setDescriptor(result)\n })\n .catch(() => {\n if (active) setDescriptor(null)\n })\n return () => { active = false }\n }, [providerKey])\n\n const fields = descriptor?.sessionConfig?.fields ?? []\n if (!providerKey) {\n return (\n <Alert variant=\"info\">\n <AlertDescription>\n {t('checkout.gatewaySettings.notices.chooseProvider')}\n </AlertDescription>\n </Alert>\n )\n }\n if (!fields.length) {\n return (\n <Alert variant=\"info\">\n <AlertDescription>\n {t('checkout.gatewaySettings.notices.noSettings')}\n </AlertDescription>\n </Alert>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {fields.map((field) => {\n const currentValue = value?.[field.key]\n return (\n <div key={field.key} className=\"space-y-2 rounded-lg border border-border/70 bg-muted/30 p-3\">\n <Label>{field.label}</Label>\n {field.type === 'select' ? (\n <select\n className=\"w-full rounded-md border bg-background px-3 py-2 text-sm\"\n value={typeof currentValue === 'string' ? currentValue : ''}\n onChange={(event) => onChange({ ...(value ?? {}), [field.key]: event.target.value })}\n >\n <option value=\"\">{t('checkout.gatewaySettings.selectPlaceholder')}</option>\n {(field.options ?? []).map((option) => (\n <option key={option.value} value={option.value}>{option.label}</option>\n ))}\n </select>\n ) : field.type === 'multiselect' ? (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {(field.options ?? []).map((option) => {\n const selectedValues = Array.isArray(currentValue)\n ? currentValue.filter((entry): entry is string => typeof entry === 'string')\n : []\n const checked = selectedValues.includes(option.value)\n return (\n <label\n key={option.value}\n className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm\"\n >\n <input\n type=\"checkbox\"\n checked={checked}\n onChange={() => toggleMultiselectValue(field.key, option.value)}\n />\n <span>{option.label}</span>\n </label>\n )\n })}\n </div>\n ) : field.type === 'boolean' ? (\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"checkbox\"\n checked={currentValue === true}\n onChange={(event) => onChange({ ...(value ?? {}), [field.key]: event.target.checked })}\n />\n {t('checkout.common.enabled')}\n </label>\n ) : field.type === 'textarea' ? (\n <Textarea\n value={typeof currentValue === 'string' ? currentValue : ''}\n onChange={(event) => onChange({ ...(value ?? {}), [field.key]: event.target.value })}\n />\n ) : (\n <Input\n type={field.type === 'number' ? 'number' : field.type === 'secret' ? 'password' : 'text'}\n value={typeof currentValue === 'string' || typeof currentValue === 'number' ? `${currentValue}` : ''}\n onChange={(event) => onChange({ ...(value ?? {}), [field.key]: event.target.value })}\n />\n )}\n {field.description ? <p className=\"text-xs text-muted-foreground\">{field.description}</p> : null}\n </div>\n )\n })}\n </div>\n )\n}\n\nexport default GatewaySettingsFields\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Alert, AlertDescription } from '@open-mercato/ui/primitives/alert'\nimport { Textarea } from '@open-mercato/ui/primitives/textarea'\nimport { Checkbox } from '@open-mercato/ui/primitives/checkbox'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\n\ntype Descriptor = {\n providerKey: string\n label: string\n sessionConfig?: {\n fields?: Array<{\n key: string\n label: string\n type: 'text' | 'number' | 'select' | 'multiselect' | 'boolean' | 'textarea' | 'secret' | 'url'\n description?: string\n options?: Array<{ value: string; label: string }>\n }>\n }\n}\n\ntype Props = {\n providerKey: string | null | undefined\n value: Record<string, unknown> | null | undefined\n onChange: (next: Record<string, unknown>) => void\n}\n\nexport function GatewaySettingsFields({ providerKey, value, onChange }: Props) {\n const t = useT()\n const [descriptor, setDescriptor] = React.useState<Descriptor | null>(null)\n\n const patchSetting = React.useCallback(\n (fieldKey: string, nextValue: unknown) => {\n const next = { ...(value ?? {}) }\n if (nextValue === undefined || nextValue === null || nextValue === '') {\n delete next[fieldKey]\n } else {\n next[fieldKey] = nextValue\n }\n onChange(next)\n },\n [onChange, value],\n )\n\n const toggleMultiselectValue = React.useCallback(\n (fieldKey: string, optionValue: string) => {\n const current = Array.isArray(value?.[fieldKey])\n ? value?.[fieldKey].filter((entry): entry is string => typeof entry === 'string')\n : []\n const next = current.includes(optionValue)\n ? current.filter((entry) => entry !== optionValue)\n : [...current, optionValue]\n patchSetting(fieldKey, next.length ? next : undefined)\n },\n [patchSetting, value],\n )\n\n React.useEffect(() => {\n let active = true\n if (!providerKey) {\n setDescriptor(null)\n return () => { active = false }\n }\n void readApiResultOrThrow<Descriptor>(`/api/payment_gateways/providers/${encodeURIComponent(providerKey)}`)\n .then((result) => {\n if (active) setDescriptor(result)\n })\n .catch(() => {\n if (active) setDescriptor(null)\n })\n return () => { active = false }\n }, [providerKey])\n\n const fields = descriptor?.sessionConfig?.fields ?? []\n if (!providerKey) {\n return (\n <Alert variant=\"info\">\n <AlertDescription>\n {t('checkout.gatewaySettings.notices.chooseProvider')}\n </AlertDescription>\n </Alert>\n )\n }\n if (!fields.length) {\n return (\n <Alert variant=\"info\">\n <AlertDescription>\n {t('checkout.gatewaySettings.notices.noSettings')}\n </AlertDescription>\n </Alert>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {fields.map((field) => {\n const currentValue = value?.[field.key]\n return (\n <div key={field.key} className=\"space-y-2 rounded-lg border border-border/70 bg-muted/30 p-3\">\n <Label>{field.label}</Label>\n {field.type === 'select' ? (\n <Select\n value={typeof currentValue === 'string' ? currentValue : ''}\n onValueChange={(next) => patchSetting(field.key, next)}\n >\n <SelectTrigger>\n <SelectValue placeholder={t('checkout.gatewaySettings.selectPlaceholder')} />\n </SelectTrigger>\n <SelectContent>\n {(field.options ?? []).map((option) => (\n <SelectItem key={option.value} value={option.value}>{option.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : field.type === 'multiselect' ? (\n <div className=\"grid gap-2 sm:grid-cols-2\">\n {(field.options ?? []).map((option) => {\n const selectedValues = Array.isArray(currentValue)\n ? currentValue.filter((entry): entry is string => typeof entry === 'string')\n : []\n const checked = selectedValues.includes(option.value)\n return (\n <label\n key={option.value}\n className=\"flex items-center gap-2 rounded-md border bg-background px-3 py-2 text-sm\"\n >\n <Checkbox\n checked={checked}\n onCheckedChange={() => toggleMultiselectValue(field.key, option.value)}\n />\n <span>{option.label}</span>\n </label>\n )\n })}\n </div>\n ) : field.type === 'boolean' ? (\n <label className=\"flex items-center gap-2 text-sm\">\n <Checkbox\n checked={currentValue === true}\n onCheckedChange={(next) => patchSetting(field.key, next === true)}\n />\n {t('checkout.common.enabled')}\n </label>\n ) : field.type === 'textarea' ? (\n <Textarea\n value={typeof currentValue === 'string' ? currentValue : ''}\n onChange={(event) => patchSetting(field.key, event.target.value)}\n />\n ) : (\n <Input\n type={field.type === 'number' ? 'number' : field.type === 'secret' ? 'password' : 'text'}\n value={typeof currentValue === 'string' || typeof currentValue === 'number' ? `${currentValue}` : ''}\n onChange={(event) => patchSetting(field.key, event.target.value)}\n />\n )}\n {field.description ? <p className=\"text-xs text-muted-foreground\">{field.description}</p> : null}\n </div>\n )\n })}\n </div>\n )\n}\n\nexport default GatewaySettingsFields\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -24,7 +24,9 @@ import { CrudForm } from "@open-mercato/ui/backend/CrudForm";
24
24
  import { ComboboxInput } from "@open-mercato/ui/backend/inputs";
25
25
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
26
26
  import { SwitchableMarkdownInput } from "@open-mercato/ui/backend/inputs";
27
- import { apiCall, apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
27
+ import { apiCall, apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
28
+ import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
29
+ import { surfaceRecordConflict } from "@open-mercato/ui/backend/conflicts";
28
30
  import { collectCustomFieldValues } from "@open-mercato/ui/backend/utils/customFieldValues";
29
31
  import { Button } from "@open-mercato/ui/primitives/button";
30
32
  import { ColorPicker } from "@open-mercato/ui/primitives/color-picker";
@@ -203,6 +205,7 @@ function normalizeFormValues(value, t) {
203
205
  primaryColor: readString(source.primaryColor).trim() || defaults.primaryColor,
204
206
  secondaryColor: readString(source.secondaryColor).trim() || defaults.secondaryColor,
205
207
  backgroundColor: readString(source.backgroundColor).trim() || defaults.backgroundColor,
208
+ gatewayProviderKey: readString(source.gatewayProviderKey).trim(),
206
209
  gatewaySettings: isRecord(source.gatewaySettings) ? source.gatewaySettings : {},
207
210
  customFieldsetCode: readString(source.customFieldsetCode).trim() || null,
208
211
  collectCustomerDetails: readBoolean(source.collectCustomerDetails, true),
@@ -1419,11 +1422,20 @@ function LinkTemplateForm({ mode, recordId }) {
1419
1422
  customFields: collectCustomFieldValues(values)
1420
1423
  };
1421
1424
  const endpoint = `/api/checkout/${mode === "link" ? "links" : "templates"}${recordId ? `/${encodeURIComponent(recordId)}` : ""}`;
1422
- const response = await readApiResultOrThrow(endpoint, {
1423
- method: recordId ? "PUT" : "POST",
1424
- headers: { "Content-Type": "application/json" },
1425
- body: JSON.stringify(payload)
1426
- });
1425
+ let response;
1426
+ try {
1427
+ response = await withScopedApiRequestHeaders(
1428
+ recordId ? buildOptimisticLockHeader(readString(initialValues?.updatedAt) || null) : {},
1429
+ () => readApiResultOrThrow(endpoint, {
1430
+ method: recordId ? "PUT" : "POST",
1431
+ headers: { "Content-Type": "application/json" },
1432
+ body: JSON.stringify(payload)
1433
+ })
1434
+ );
1435
+ } catch (error) {
1436
+ if (surfaceRecordConflict(error, t)) return;
1437
+ throw error;
1438
+ }
1427
1439
  const targetId = recordId ?? (typeof response?.id === "string" ? response.id : null);
1428
1440
  const logoAttachmentId = readString(values.logoAttachmentId);
1429
1441
  if (!recordId && targetId && logoAttachmentId && logoAttachmentId !== initialLogoAttachmentIdRef.current) {
@@ -1459,7 +1471,15 @@ function LinkTemplateForm({ mode, recordId }) {
1459
1471
  )}&type=success` : `/backend/checkout/templates?flash=${encodeURIComponent(t("checkout.common.flash.saved"))}&type=success`;
1460
1472
  },
1461
1473
  onDelete: recordId ? async () => {
1462
- await apiCallOrThrow(`/api/checkout/${mode === "link" ? "links" : "templates"}/${encodeURIComponent(recordId)}`, { method: "DELETE" });
1474
+ try {
1475
+ await withScopedApiRequestHeaders(
1476
+ buildOptimisticLockHeader(readString(initialValues?.updatedAt) || null),
1477
+ () => apiCallOrThrow(`/api/checkout/${mode === "link" ? "links" : "templates"}/${encodeURIComponent(recordId)}`, { method: "DELETE" })
1478
+ );
1479
+ } catch (error) {
1480
+ if (surfaceRecordConflict(error, t)) return;
1481
+ throw error;
1482
+ }
1463
1483
  window.location.href = mode === "link" ? `/backend/checkout/pay-links?flash=${encodeURIComponent(t("checkout.common.flash.deleted"))}&type=success` : `/backend/checkout/templates?flash=${encodeURIComponent(t("checkout.common.flash.deleted"))}&type=success`;
1464
1484
  } : void 0
1465
1485
  },