@open-mercato/core 0.10.1-develop.7863.1.335fb1fe52 → 0.10.1-develop.7865.1.9a16aa6194
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/audit_logs/api/audit-logs/actions/redo/route.js +1 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +1 -1
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +0 -1
- package/src/modules/sales/components/documents/PaymentsSection.tsx +1 -1
|
@@ -4,10 +4,10 @@ import { resolveSingleOrganizationIdOrDeny } from "@open-mercato/shared/lib/auth
|
|
|
4
4
|
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
5
5
|
import { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from "@open-mercato/core/modules/directory/utils/organizationScope";
|
|
6
6
|
import { isCrudHttpError, translateCrudErrorBody } from "@open-mercato/shared/lib/crud/errors";
|
|
7
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
7
8
|
import { serializeOperationMetadata } from "@open-mercato/shared/lib/commands/operationMetadata";
|
|
8
9
|
import { z } from "zod";
|
|
9
10
|
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
10
|
-
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
11
11
|
import { getCommandInterceptorHttpRejection } from "@open-mercato/shared/lib/commands/errors";
|
|
12
12
|
import { authorizeAuditReplayWithEntityManager } from "@open-mercato/core/modules/audit_logs/lib/replayAuthorization";
|
|
13
13
|
import {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/audit_logs/api/audit-logs/actions/redo/route.ts"],
|
|
4
|
-
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveSingleOrganizationIdOrDeny } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { isCrudHttpError, translateCrudErrorBody } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext, CommandLogMetadata } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { AwilixContainer } from 'awilix'\nimport type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { authorizeAuditReplayWithEntityManager } from '@open-mercato/core/modules/audit_logs/lib/replayAuthorization'\nimport {\n actionLogBelongsToAuth,\n resolveCanonicalAuthSubject,\n resolveActionLogActorSubject,\n} from '@open-mercato/core/modules/audit_logs/lib/actorSubject'\n\nconst logger = createLogger('audit_logs').child({ component: 'redo' })\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.redo_self'] },\n}\n\ntype RedoRequestBody = {\n logId?: string\n}\n\nconst redoRequestSchema = z.object({\n logId: z.string().min(1).describe('Identifier of the previously undone action log'),\n})\n\nconst redoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().nullable().describe('Identifier of the new redo log entry, if available'),\n undoToken: z.string().nullable().describe('New undo token associated with the redone action'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const authSubject = resolveCanonicalAuthSubject(auth)\n if (!authSubject) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as RedoRequestBody | null\n const logId = typeof body?.logId === 'string' ? body.logId.trim() : ''\n if (!logId) return NextResponse.json({ error: 'Invalid log id' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId, scope } = await resolveFeatureCheckContext({ container, auth, request: req })\n let singleOrganizationId: string | null\n try {\n singleOrganizationId = organizationId ?? resolveSingleOrganizationIdOrDeny(scope, auth)\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n\n const canRedoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.redo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const scopedOrgId = canRedoTenant ? organizationId ?? null : singleOrganizationId\n const log = await logs.findById(logId)\n\n if (!log || log.executionState !== 'undone') {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n const logActorSubject = resolveActionLogActorSubject(log)\n const isLegacyApiKeyOwner = log.actorUserId === authSubject.storageId\n && authSubject.kind === 'api_key'\n && log.contextJson?.actorSubject === undefined\n if (log.actorUserId && !logActorSubject && !isLegacyApiKeyOwner) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (log.actorUserId && !actionLogBelongsToAuth(log, auth) && !canRedoTenant) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.redo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never redo a tenant-scoped row. Mirrors the\n // hardened undo route (issue #2685, ported in #2931).\n if (log.tenantId && log.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Tenant-level redoers may redo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685, ported in #2931).\n const orgScopeMismatch = canRedoTenant\n ? Boolean(log.organizationId && scopedOrgId && log.organizationId !== scopedOrgId)\n : Boolean(log.organizationId && log.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n const lookupActorId = canRedoTenant\n ? (logActorSubject ?? (isLegacyApiKeyOwner ? authSubject.subject : auth.sub))\n : authSubject.subject\n const latestUndoneOrganizationId = log.organizationId ?? null\n const latestUndone = await logs.latestUndoneForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: latestUndoneOrganizationId,\n })\n if (!latestUndone || latestUndone.id !== log.id) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (!rbac) return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n const replayRbac = rbac\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n ctx.replayTransactionGuard = ({ logEntry, transactionalEm }) =>\n authorizeAuditReplayWithEntityManager(transactionalEm, replayRbac, logEntry, {\n auth,\n organizationId,\n selfFeature: 'audit_logs.redo_self',\n tenantFeature: 'audit_logs.redo_tenant',\n unavailableMessage: 'Redo target not available',\n })\n const contextRecord = log.contextJson && typeof log.contextJson === 'object' ? (log.contextJson as Record<string, unknown>) : null\n const cacheAliasesRaw = Array.isArray(contextRecord?.cacheAliases as unknown[])\n ? (contextRecord!.cacheAliases as unknown[])\n : []\n const cacheAliases = cacheAliasesRaw\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n .map((value) => value.trim())\n const metadataContext: Record<string, unknown> = {\n historyAction: 'redo',\n sourceLogId: log.id,\n sourceCommandId: log.commandId,\n }\n if (cacheAliases.length) metadataContext.cacheAliases = cacheAliases\n const metadata: CommandLogMetadata = {\n tenantId: log.tenantId,\n organizationId: log.organizationId,\n actorUserId: auth.sub,\n actionLabel: log.actionLabel,\n resourceKind: log.resourceKind,\n resourceId: log.resourceId,\n context: metadataContext,\n }\n const resolvedInput = resolveRedoInput(log.commandPayload, log)\n if (!resolvedInput) {\n return NextResponse.json({ error: 'Redo data unavailable for this action' }, { status: 400 })\n }\n const commandInput = resolvedInput\n const { logEntry, replaySourceFinalized } = await commandBus.execute(log.commandId, {\n input: commandInput,\n ctx,\n metadata,\n redoLogEntry: log,\n })\n if (replaySourceFinalized !== true) await logs.markRedone(log.id)\n const actionLog = asActionLog(logEntry)\n const response = NextResponse.json({\n ok: true,\n logId: actionLog?.id ?? null,\n undoToken: actionLog?.undoToken ?? null,\n })\n if (actionLog?.undoToken && actionLog.id) {\n const createdAt = actionLog.createdAt instanceof Date\n ? actionLog.createdAt.toISOString()\n : (typeof actionLog.createdAt === 'string' ? actionLog.createdAt : new Date().toISOString())\n response.headers.set('x-om-operation', serializeOperationMetadata({\n id: actionLog.id,\n undoToken: actionLog.undoToken,\n commandId: actionLog.commandId ?? log.commandId,\n actionLabel: actionLog.actionLabel ?? log.actionLabel ?? null,\n resourceKind: typeof actionLog.resourceKind === 'string' ? actionLog.resourceKind : log.resourceKind ?? null,\n resourceId: typeof actionLog.resourceId === 'string' ? actionLog.resourceId : log.resourceId ?? null,\n executedAt: createdAt,\n }))\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n logger.warn('Redo rejected', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json(translateCrudErrorBody(err.body, translate), { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n logger.error('Redo failed', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json({ error: translate('audit_logs.error.redo_failed', 'Redo failed') }, { status: 400 })\n }\n}\n\nasync function createRuntimeContext(container: AwilixContainer, auth: AuthContext, request: Request): Promise<CommandRuntimeContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope.selectedId,\n organizationIds: scope.filterIds,\n request,\n }\n}\n\nfunction asActionLog(entry: unknown): ActionLog | null {\n if (!entry || typeof entry !== 'object') return null\n if (typeof (entry as { id?: unknown }).id !== 'string') return null\n return entry as ActionLog\n}\n\nfunction resolveRedoInput(payload: unknown, log: ActionLog): unknown | null {\n if (payload && typeof payload === 'object' && !Array.isArray(payload) && '__redoInput' in payload) {\n const envelope = payload as { __redoInput?: unknown }\n return envelope.__redoInput ?? {}\n }\n const updateFallback = deriveUpdateInput(log)\n if (updateFallback) return updateFallback\n return null\n}\n\nfunction deriveUpdateInput(log: ActionLog): Record<string, unknown> | null {\n if (!log.commandId.endsWith('.update')) return null\n if (!log.resourceId) return null\n const changes = log.changesJson\n if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return { id: log.resourceId }\n const payload: Record<string, unknown> = { id: log.resourceId }\n for (const [key, value] of Object.entries(changes)) {\n if (value && typeof value === 'object' && !Array.isArray(value) && 'to' in value) {\n payload[key] = (value as Record<string, unknown>).to\n } else {\n payload[key] = value\n }\n }\n return payload\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Redo a previously undone action',\n description: 'Replays the command associated with a recently undone action, reapplying the change and issuing a fresh undo token.',\n methods: {\n POST: {\n summary: 'Redo by action log id',\n description:\n 'Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: redoRequestSchema,\n },\n responses: [\n { status: 200, description: 'Redo executed successfully', schema: redoResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Log not eligible for redo', schema: errorSchema },\n { status: 401, description: 'Authentication required', schema: errorSchema },\n { status: 403, description: 'Redo blocked by scope checks', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA4C;AACrD,SAAS,yCAAyC;AAClD,SAAS,8BAA8B;AACvC,SAAS,4BAA4B,0CAA0C;AAG/E,SAAS,iBAAiB,8BAA8B;
|
|
4
|
+
"sourcesContent": ["import { NextResponse } from 'next/server'\nimport { getAuthFromRequest, type AuthContext } from '@open-mercato/shared/lib/auth/server'\nimport { resolveSingleOrganizationIdOrDeny } from '@open-mercato/shared/lib/auth/organizationScope'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { resolveFeatureCheckContext, resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { CommandBus } from '@open-mercato/shared/lib/commands/command-bus'\nimport { isCrudHttpError, translateCrudErrorBody } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { ActionLogService } from '@open-mercato/core/modules/audit_logs/services/actionLogService'\nimport type { CommandRuntimeContext, CommandLogMetadata } from '@open-mercato/shared/lib/commands'\nimport { serializeOperationMetadata } from '@open-mercato/shared/lib/commands/operationMetadata'\nimport type { AwilixContainer } from 'awilix'\nimport type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entities'\nimport { z } from 'zod'\nimport type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\nimport { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'\nimport { authorizeAuditReplayWithEntityManager } from '@open-mercato/core/modules/audit_logs/lib/replayAuthorization'\nimport {\n actionLogBelongsToAuth,\n resolveCanonicalAuthSubject,\n resolveActionLogActorSubject,\n} from '@open-mercato/core/modules/audit_logs/lib/actorSubject'\n\nconst logger = createLogger('audit_logs').child({ component: 'redo' })\n\nexport const metadata = {\n POST: { requireAuth: true, requireFeatures: ['audit_logs.redo_self'] },\n}\n\ntype RedoRequestBody = {\n logId?: string\n}\n\nconst redoRequestSchema = z.object({\n logId: z.string().min(1).describe('Identifier of the previously undone action log'),\n})\n\nconst redoResponseSchema = z.object({\n ok: z.literal(true),\n logId: z.string().nullable().describe('Identifier of the new redo log entry, if available'),\n undoToken: z.string().nullable().describe('New undo token associated with the redone action'),\n})\n\nconst errorSchema = z.object({\n error: z.string(),\n})\n\nexport async function POST(req: Request) {\n const auth = await getAuthFromRequest(req)\n if (!auth) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n const authSubject = resolveCanonicalAuthSubject(auth)\n if (!authSubject) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })\n\n const body = (await req.json().catch(() => null)) as RedoRequestBody | null\n const logId = typeof body?.logId === 'string' ? body.logId.trim() : ''\n if (!logId) return NextResponse.json({ error: 'Invalid log id' }, { status: 400 })\n\n const container = await createRequestContainer()\n const commandBus = (container.resolve('commandBus') as CommandBus)\n const logs = (container.resolve('actionLogService') as ActionLogService)\n let rbac: RbacService | null = null\n try {\n rbac = (container.resolve('rbacService') as RbacService)\n } catch {\n rbac = null\n }\n\n const { organizationId, scope } = await resolveFeatureCheckContext({ container, auth, request: req })\n let singleOrganizationId: string | null\n try {\n singleOrganizationId = organizationId ?? resolveSingleOrganizationIdOrDeny(scope, auth)\n } catch (err) {\n if (isCrudHttpError(err)) return NextResponse.json(err.body, { status: err.status })\n throw err\n }\n\n const canRedoTenant = rbac\n ? await rbac.userHasAllFeatures(auth.sub, ['audit_logs.redo_tenant'], {\n tenantId: auth.tenantId ?? null,\n organizationId,\n })\n : false\n\n const scopedOrgId = canRedoTenant ? organizationId ?? null : singleOrganizationId\n const log = await logs.findById(logId)\n\n if (!log || log.executionState !== 'undone') {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n const logActorSubject = resolveActionLogActorSubject(log)\n const isLegacyApiKeyOwner = log.actorUserId === authSubject.storageId\n && authSubject.kind === 'api_key'\n && log.contextJson?.actorSubject === undefined\n if (log.actorUserId && !logActorSubject && !isLegacyApiKeyOwner) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (log.actorUserId && !actionLogBelongsToAuth(log, auth) && !canRedoTenant) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Fail closed on tenant scope: `audit_logs.redo_tenant` only widens scope WITHIN a\n // tenant, never across tenants, so a tenant-scoped target always requires a caller\n // bound to that same tenant. A caller whose tenantId is null (tenant-less global\n // account or unscoped API key) must never redo a tenant-scoped row. Mirrors the\n // hardened undo route (issue #2685, ported in #2931).\n if (log.tenantId && log.tenantId !== (auth.tenantId ?? null)) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n // Tenant-level redoers may redo across organizations within the tenant, so an\n // unresolved (null) caller org is allowed and only an explicit mismatch is rejected.\n // Every other caller must resolve to the target's own organization \u2014 a null caller\n // org must not bypass an org-scoped target (issue #2685, ported in #2931).\n const orgScopeMismatch = canRedoTenant\n ? Boolean(log.organizationId && scopedOrgId && log.organizationId !== scopedOrgId)\n : Boolean(log.organizationId && log.organizationId !== scopedOrgId)\n if (orgScopeMismatch) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n\n const lookupActorId = canRedoTenant\n ? (logActorSubject ?? (isLegacyApiKeyOwner ? authSubject.subject : auth.sub))\n : authSubject.subject\n const latestUndoneOrganizationId = log.organizationId ?? null\n const latestUndone = await logs.latestUndoneForActor(lookupActorId, {\n tenantId: auth.tenantId ?? null,\n organizationId: latestUndoneOrganizationId,\n })\n if (!latestUndone || latestUndone.id !== log.id) {\n return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n }\n if (!rbac) return NextResponse.json({ error: 'Redo target not available' }, { status: 400 })\n const replayRbac = rbac\n\n try {\n const ctx = await createRuntimeContext(container, auth, req)\n ctx.replayTransactionGuard = ({ logEntry, transactionalEm }) =>\n authorizeAuditReplayWithEntityManager(transactionalEm, replayRbac, logEntry, {\n auth,\n organizationId,\n selfFeature: 'audit_logs.redo_self',\n tenantFeature: 'audit_logs.redo_tenant',\n unavailableMessage: 'Redo target not available',\n })\n const contextRecord = log.contextJson && typeof log.contextJson === 'object' ? (log.contextJson as Record<string, unknown>) : null\n const cacheAliasesRaw = Array.isArray(contextRecord?.cacheAliases as unknown[])\n ? (contextRecord!.cacheAliases as unknown[])\n : []\n const cacheAliases = cacheAliasesRaw\n .filter((value): value is string => typeof value === 'string' && value.trim().length > 0)\n .map((value) => value.trim())\n const metadataContext: Record<string, unknown> = {\n historyAction: 'redo',\n sourceLogId: log.id,\n sourceCommandId: log.commandId,\n }\n if (cacheAliases.length) metadataContext.cacheAliases = cacheAliases\n const metadata: CommandLogMetadata = {\n tenantId: log.tenantId,\n organizationId: log.organizationId,\n actorUserId: auth.sub,\n actionLabel: log.actionLabel,\n resourceKind: log.resourceKind,\n resourceId: log.resourceId,\n context: metadataContext,\n }\n const resolvedInput = resolveRedoInput(log.commandPayload, log)\n if (!resolvedInput) {\n return NextResponse.json({ error: 'Redo data unavailable for this action' }, { status: 400 })\n }\n const commandInput = resolvedInput\n const { logEntry, replaySourceFinalized } = await commandBus.execute(log.commandId, {\n input: commandInput,\n ctx,\n metadata,\n redoLogEntry: log,\n })\n if (replaySourceFinalized !== true) await logs.markRedone(log.id)\n const actionLog = asActionLog(logEntry)\n const response = NextResponse.json({\n ok: true,\n logId: actionLog?.id ?? null,\n undoToken: actionLog?.undoToken ?? null,\n })\n if (actionLog?.undoToken && actionLog.id) {\n const createdAt = actionLog.createdAt instanceof Date\n ? actionLog.createdAt.toISOString()\n : (typeof actionLog.createdAt === 'string' ? actionLog.createdAt : new Date().toISOString())\n response.headers.set('x-om-operation', serializeOperationMetadata({\n id: actionLog.id,\n undoToken: actionLog.undoToken,\n commandId: actionLog.commandId ?? log.commandId,\n actionLabel: actionLog.actionLabel ?? log.actionLabel ?? null,\n resourceKind: typeof actionLog.resourceKind === 'string' ? actionLog.resourceKind : log.resourceKind ?? null,\n resourceId: typeof actionLog.resourceId === 'string' ? actionLog.resourceId : log.resourceId ?? null,\n executedAt: createdAt,\n }))\n }\n return response\n } catch (err) {\n if (isCrudHttpError(err)) {\n logger.warn('Redo rejected', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json(translateCrudErrorBody(err.body, translate), { status: err.status })\n }\n const interceptorRejection = getCommandInterceptorHttpRejection(err)\n if (interceptorRejection) {\n return NextResponse.json(interceptorRejection.body, { status: interceptorRejection.status })\n }\n logger.error('Redo failed', { err })\n const { translate } = await resolveTranslations()\n return NextResponse.json({ error: translate('audit_logs.error.redo_failed', 'Redo failed') }, { status: 400 })\n }\n}\n\nasync function createRuntimeContext(container: AwilixContainer, auth: AuthContext, request: Request): Promise<CommandRuntimeContext> {\n const scope = await resolveOrganizationScopeForRequest({ container, auth, request })\n return {\n container,\n auth,\n organizationScope: scope,\n selectedOrganizationId: scope.selectedId,\n organizationIds: scope.filterIds,\n request,\n }\n}\n\nfunction asActionLog(entry: unknown): ActionLog | null {\n if (!entry || typeof entry !== 'object') return null\n if (typeof (entry as { id?: unknown }).id !== 'string') return null\n return entry as ActionLog\n}\n\nfunction resolveRedoInput(payload: unknown, log: ActionLog): unknown | null {\n if (payload && typeof payload === 'object' && !Array.isArray(payload) && '__redoInput' in payload) {\n const envelope = payload as { __redoInput?: unknown }\n return envelope.__redoInput ?? {}\n }\n const updateFallback = deriveUpdateInput(log)\n if (updateFallback) return updateFallback\n return null\n}\n\nfunction deriveUpdateInput(log: ActionLog): Record<string, unknown> | null {\n if (!log.commandId.endsWith('.update')) return null\n if (!log.resourceId) return null\n const changes = log.changesJson\n if (!changes || typeof changes !== 'object' || Array.isArray(changes)) return { id: log.resourceId }\n const payload: Record<string, unknown> = { id: log.resourceId }\n for (const [key, value] of Object.entries(changes)) {\n if (value && typeof value === 'object' && !Array.isArray(value) && 'to' in value) {\n payload[key] = (value as Record<string, unknown>).to\n } else {\n payload[key] = value\n }\n }\n return payload\n}\n\nexport const openApi: OpenApiRouteDoc = {\n summary: 'Redo a previously undone action',\n description: 'Replays the command associated with a recently undone action, reapplying the change and issuing a fresh undo token.',\n methods: {\n POST: {\n summary: 'Redo by action log id',\n description:\n 'Redoes the latest undone command owned by the caller. Requires the action to still be eligible for redo within tenant and organization scope.',\n requestBody: {\n contentType: 'application/json',\n schema: redoRequestSchema,\n },\n responses: [\n { status: 200, description: 'Redo executed successfully', schema: redoResponseSchema },\n ],\n errors: [\n { status: 400, description: 'Log not eligible for redo', schema: errorSchema },\n { status: 401, description: 'Authentication required', schema: errorSchema },\n { status: 403, description: 'Redo blocked by scope checks', schema: errorSchema },\n ],\n },\n },\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,oBAAoB;AAC7B,SAAS,0BAA4C;AACrD,SAAS,yCAAyC;AAClD,SAAS,8BAA8B;AACvC,SAAS,4BAA4B,0CAA0C;AAG/E,SAAS,iBAAiB,8BAA8B;AACxD,SAAS,2BAA2B;AAGpC,SAAS,kCAAkC;AAG3C,SAAS,SAAS;AAElB,SAAS,oBAAoB;AAC7B,SAAS,0CAA0C;AACnD,SAAS,6CAA6C;AACtD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,MAAM,SAAS,aAAa,YAAY,EAAE,MAAM,EAAE,WAAW,OAAO,CAAC;AAE9D,MAAM,WAAW;AAAA,EACtB,MAAM,EAAE,aAAa,MAAM,iBAAiB,CAAC,sBAAsB,EAAE;AACvE;AAMA,MAAM,oBAAoB,EAAE,OAAO;AAAA,EACjC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,SAAS,gDAAgD;AACpF,CAAC;AAED,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,IAAI,EAAE,QAAQ,IAAI;AAAA,EAClB,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,oDAAoD;AAAA,EAC1F,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,kDAAkD;AAC9F,CAAC;AAED,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,OAAO,EAAE,OAAO;AAClB,CAAC;AAED,eAAsB,KAAK,KAAc;AACvC,QAAM,OAAO,MAAM,mBAAmB,GAAG;AACzC,MAAI,CAAC,KAAM,QAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC9E,QAAM,cAAc,4BAA4B,IAAI;AACpD,MAAI,CAAC,YAAa,QAAO,aAAa,KAAK,EAAE,OAAO,eAAe,GAAG,EAAE,QAAQ,IAAI,CAAC;AAErF,QAAM,OAAQ,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,IAAI;AAC/C,QAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI;AACpE,MAAI,CAAC,MAAO,QAAO,aAAa,KAAK,EAAE,OAAO,iBAAiB,GAAG,EAAE,QAAQ,IAAI,CAAC;AAEjF,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,aAAc,UAAU,QAAQ,YAAY;AAClD,QAAM,OAAQ,UAAU,QAAQ,kBAAkB;AAClD,MAAI,OAA2B;AAC/B,MAAI;AACF,WAAQ,UAAU,QAAQ,aAAa;AAAA,EACzC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAM,EAAE,gBAAgB,MAAM,IAAI,MAAM,2BAA2B,EAAE,WAAW,MAAM,SAAS,IAAI,CAAC;AACpG,MAAI;AACJ,MAAI;AACF,2BAAuB,kBAAkB,kCAAkC,OAAO,IAAI;AAAA,EACxF,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,EAAG,QAAO,aAAa,KAAK,IAAI,MAAM,EAAE,QAAQ,IAAI,OAAO,CAAC;AACnF,UAAM;AAAA,EACR;AAEA,QAAM,gBAAgB,OAClB,MAAM,KAAK,mBAAmB,KAAK,KAAK,CAAC,wBAAwB,GAAG;AAAA,IAClE,UAAU,KAAK,YAAY;AAAA,IAC3B;AAAA,EACF,CAAC,IACD;AAEJ,QAAM,cAAc,gBAAgB,kBAAkB,OAAO;AAC7D,QAAM,MAAM,MAAM,KAAK,SAAS,KAAK;AAErC,MAAI,CAAC,OAAO,IAAI,mBAAmB,UAAU;AAC3C,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AACA,QAAM,kBAAkB,6BAA6B,GAAG;AACxD,QAAM,sBAAsB,IAAI,gBAAgB,YAAY,aACvD,YAAY,SAAS,aACrB,IAAI,aAAa,iBAAiB;AACvC,MAAI,IAAI,eAAe,CAAC,mBAAmB,CAAC,qBAAqB;AAC/D,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AACA,MAAI,IAAI,eAAe,CAAC,uBAAuB,KAAK,IAAI,KAAK,CAAC,eAAe;AAC3E,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AAMA,MAAI,IAAI,YAAY,IAAI,cAAc,KAAK,YAAY,OAAO;AAC5D,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AAKA,QAAM,mBAAmB,gBACrB,QAAQ,IAAI,kBAAkB,eAAe,IAAI,mBAAmB,WAAW,IAC/E,QAAQ,IAAI,kBAAkB,IAAI,mBAAmB,WAAW;AACpE,MAAI,kBAAkB;AACpB,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AAEA,QAAM,gBAAgB,gBACjB,oBAAoB,sBAAsB,YAAY,UAAU,KAAK,OACtE,YAAY;AAChB,QAAM,6BAA6B,IAAI,kBAAkB;AACzD,QAAM,eAAe,MAAM,KAAK,qBAAqB,eAAe;AAAA,IAClE,UAAU,KAAK,YAAY;AAAA,IAC3B,gBAAgB;AAAA,EAClB,CAAC;AACD,MAAI,CAAC,gBAAgB,aAAa,OAAO,IAAI,IAAI;AAC/C,WAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClF;AACA,MAAI,CAAC,KAAM,QAAO,aAAa,KAAK,EAAE,OAAO,4BAA4B,GAAG,EAAE,QAAQ,IAAI,CAAC;AAC3F,QAAM,aAAa;AAEnB,MAAI;AACF,UAAM,MAAM,MAAM,qBAAqB,WAAW,MAAM,GAAG;AAC3D,QAAI,yBAAyB,CAAC,EAAE,UAAAA,WAAU,gBAAgB,MACxD,sCAAsC,iBAAiB,YAAYA,WAAU;AAAA,MAC3E;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb,eAAe;AAAA,MACf,oBAAoB;AAAA,IACtB,CAAC;AACH,UAAM,gBAAgB,IAAI,eAAe,OAAO,IAAI,gBAAgB,WAAY,IAAI,cAA0C;AAC9H,UAAM,kBAAkB,MAAM,QAAQ,eAAe,YAAyB,IACzE,cAAe,eAChB,CAAC;AACL,UAAM,eAAe,gBAClB,OAAO,CAAC,UAA2B,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS,CAAC,EACvF,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC;AAC9B,UAAM,kBAA2C;AAAA,MAC/C,eAAe;AAAA,MACf,aAAa,IAAI;AAAA,MACjB,iBAAiB,IAAI;AAAA,IACvB;AACA,QAAI,aAAa,OAAQ,iBAAgB,eAAe;AACxD,UAAMC,YAA+B;AAAA,MACnC,UAAU,IAAI;AAAA,MACd,gBAAgB,IAAI;AAAA,MACpB,aAAa,KAAK;AAAA,MAClB,aAAa,IAAI;AAAA,MACjB,cAAc,IAAI;AAAA,MAClB,YAAY,IAAI;AAAA,MAChB,SAAS;AAAA,IACX;AACA,UAAM,gBAAgB,iBAAiB,IAAI,gBAAgB,GAAG;AAC9D,QAAI,CAAC,eAAe;AAClB,aAAO,aAAa,KAAK,EAAE,OAAO,wCAAwC,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,IAC9F;AACA,UAAM,eAAe;AACrB,UAAM,EAAE,UAAU,sBAAsB,IAAI,MAAM,WAAW,QAAQ,IAAI,WAAW;AAAA,MAClF,OAAO;AAAA,MACP;AAAA,MACA,UAAAA;AAAA,MACA,cAAc;AAAA,IAChB,CAAC;AACD,QAAI,0BAA0B,KAAM,OAAM,KAAK,WAAW,IAAI,EAAE;AAChE,UAAM,YAAY,YAAY,QAAQ;AACtC,UAAM,WAAW,aAAa,KAAK;AAAA,MACjC,IAAI;AAAA,MACJ,OAAO,WAAW,MAAM;AAAA,MACxB,WAAW,WAAW,aAAa;AAAA,IACrC,CAAC;AACD,QAAI,WAAW,aAAa,UAAU,IAAI;AACxC,YAAM,YAAY,UAAU,qBAAqB,OAC7C,UAAU,UAAU,YAAY,IAC/B,OAAO,UAAU,cAAc,WAAW,UAAU,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5F,eAAS,QAAQ,IAAI,kBAAkB,2BAA2B;AAAA,QAChE,IAAI,UAAU;AAAA,QACd,WAAW,UAAU;AAAA,QACrB,WAAW,UAAU,aAAa,IAAI;AAAA,QACtC,aAAa,UAAU,eAAe,IAAI,eAAe;AAAA,QACzD,cAAc,OAAO,UAAU,iBAAiB,WAAW,UAAU,eAAe,IAAI,gBAAgB;AAAA,QACxG,YAAY,OAAO,UAAU,eAAe,WAAW,UAAU,aAAa,IAAI,cAAc;AAAA,QAChG,YAAY;AAAA,MACd,CAAC,CAAC;AAAA,IACJ;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AACZ,QAAI,gBAAgB,GAAG,GAAG;AACxB,aAAO,KAAK,iBAAiB,EAAE,IAAI,CAAC;AACpC,YAAM,EAAE,WAAAC,WAAU,IAAI,MAAM,oBAAoB;AAChD,aAAO,aAAa,KAAK,uBAAuB,IAAI,MAAMA,UAAS,GAAG,EAAE,QAAQ,IAAI,OAAO,CAAC;AAAA,IAC9F;AACA,UAAM,uBAAuB,mCAAmC,GAAG;AACnE,QAAI,sBAAsB;AACxB,aAAO,aAAa,KAAK,qBAAqB,MAAM,EAAE,QAAQ,qBAAqB,OAAO,CAAC;AAAA,IAC7F;AACA,WAAO,MAAM,eAAe,EAAE,IAAI,CAAC;AACnC,UAAM,EAAE,UAAU,IAAI,MAAM,oBAAoB;AAChD,WAAO,aAAa,KAAK,EAAE,OAAO,UAAU,gCAAgC,aAAa,EAAE,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/G;AACF;AAEA,eAAe,qBAAqB,WAA4B,MAAmB,SAAkD;AACnI,QAAM,QAAQ,MAAM,mCAAmC,EAAE,WAAW,MAAM,QAAQ,CAAC;AACnF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,mBAAmB;AAAA,IACnB,wBAAwB,MAAM;AAAA,IAC9B,iBAAiB,MAAM;AAAA,IACvB;AAAA,EACF;AACF;AAEA,SAAS,YAAY,OAAkC;AACrD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,MAAI,OAAQ,MAA2B,OAAO,SAAU,QAAO;AAC/D,SAAO;AACT;AAEA,SAAS,iBAAiB,SAAkB,KAAgC;AAC1E,MAAI,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,KAAK,iBAAiB,SAAS;AACjG,UAAM,WAAW;AACjB,WAAO,SAAS,eAAe,CAAC;AAAA,EAClC;AACA,QAAM,iBAAiB,kBAAkB,GAAG;AAC5C,MAAI,eAAgB,QAAO;AAC3B,SAAO;AACT;AAEA,SAAS,kBAAkB,KAAgD;AACzE,MAAI,CAAC,IAAI,UAAU,SAAS,SAAS,EAAG,QAAO;AAC/C,MAAI,CAAC,IAAI,WAAY,QAAO;AAC5B,QAAM,UAAU,IAAI;AACpB,MAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO,EAAE,IAAI,IAAI,WAAW;AACnG,QAAM,UAAmC,EAAE,IAAI,IAAI,WAAW;AAC9D,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,KAAK,QAAQ,OAAO;AAChF,cAAQ,GAAG,IAAK,MAAkC;AAAA,IACpD,OAAO;AACL,cAAQ,GAAG,IAAI;AAAA,IACjB;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,UAA2B;AAAA,EACtC,SAAS;AAAA,EACT,aAAa;AAAA,EACb,SAAS;AAAA,IACP,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,aACE;AAAA,MACF,aAAa;AAAA,QACX,aAAa;AAAA,QACb,QAAQ;AAAA,MACV;AAAA,MACA,WAAW;AAAA,QACT,EAAE,QAAQ,KAAK,aAAa,8BAA8B,QAAQ,mBAAmB;AAAA,MACvF;AAAA,MACA,QAAQ;AAAA,QACN,EAAE,QAAQ,KAAK,aAAa,6BAA6B,QAAQ,YAAY;AAAA,QAC7E,EAAE,QAAQ,KAAK,aAAa,2BAA2B,QAAQ,YAAY;AAAA,QAC3E,EAAE,QAAQ,KAAK,aAAa,gCAAgC,QAAQ,YAAY;AAAA,MAClF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": ["logEntry", "metadata", "translate"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sales/components/documents/PaymentsSection.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { LoadingMessage, ErrorMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { handleSectionMutationError, readRowUpdatedAt } from './optimisticLock'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { formatDisplayDate, formatDisplayDateTime, toUtcDateInputValue } from '@open-mercato/ui/primitives/date-format'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { emitSalesDocumentTotalsRefresh } from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'\nimport { extensionPoints } from '@open-mercato/core/modules/sales/extension-points'\nimport { PaymentDialog, type PaymentFormData, type PaymentTotals } from './PaymentDialog'\nimport { extractCustomFieldValues } from './customFieldHelpers'\nimport { Plus } from 'lucide-react'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype PaymentRow = {\n id: string\n updatedAt: string | null\n paymentReference: string | null\n paymentMethodId: string | null\n paymentMethodName: string | null\n status: string | null\n statusEntryId: string | null\n statusLabel: string | null\n amount: number\n currencyCode: string | null\n receivedAt: string | null\n createdAt: string | null\n customValues?: Record<string, unknown> | null\n customFieldSetId?: string | null\n}\n\ntype SalesDocumentPaymentsSectionProps = {\n orderId: string\n currencyCode: string | null | undefined\n organizationId?: string | null\n tenantId?: string | null\n documentUpdatedAt?: string | null\n onActionChange?: (action: SectionAction | null) => void\n onTotalsChange?: () => void\n onPaymentsChange?: (payments: PaymentRow[]) => void\n}\n\nfunction normalizeNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n if (!Number.isNaN(parsed)) return parsed\n }\n return 0\n}\n\nfunction formatMoney(value: number, currency: string | null | undefined, locale?: string): string {\n if (!currency || currency.trim().length !== 3) return value.toFixed(2)\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value)\n } catch {\n return `${currency.toUpperCase()} ${value.toFixed(2)}`\n }\n}\n\nexport function SalesDocumentPaymentsSection({\n orderId,\n currencyCode,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n documentUpdatedAt,\n onActionChange,\n onTotalsChange,\n onPaymentsChange,\n}: SalesDocumentPaymentsSectionProps) {\n const t = useT()\n const locale = useLocale()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null\n const [payments, setPayments] = React.useState<PaymentRow[]>([])\n const [loading, setLoading] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [editingPayment, setEditingPayment] = React.useState<PaymentFormData | null>(null)\n const onPaymentsChangeRef = React.useRef<typeof onPaymentsChange>(onPaymentsChange)\n\n React.useEffect(() => {\n onPaymentsChangeRef.current = onPaymentsChange\n }, [onPaymentsChange])\n\n const addActionLabel = t('sales.documents.payments.add', 'Add payment')\n const editActionLabel = t('sales.documents.payments.edit', 'Edit payment')\n const deleteActionLabel = t('sales.documents.payments.delete', 'Delete payment')\n\n const loadPayments = React.useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payments?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n if (response.ok && Array.isArray(response.result?.items)) {\n const mapped = response.result.items.flatMap<PaymentRow>((item) => {\n if (typeof item.id !== 'string') return []\n const customValues =\n item && typeof item === 'object'\n ? extractCustomFieldValues(item as Record<string, unknown>)\n : {}\n const record: PaymentRow = {\n id: item.id,\n updatedAt: readRowUpdatedAt(item),\n paymentReference: typeof item.payment_reference === 'string' ? item.payment_reference : null,\n paymentMethodId: typeof item.payment_method_id === 'string' ? item.payment_method_id : null,\n paymentMethodName:\n typeof item.payment_method_name === 'string'\n ? item.payment_method_name\n : typeof item.payment_method_code === 'string'\n ? item.payment_method_code\n : null,\n status: typeof item.status === 'string' ? item.status : null,\n statusEntryId:\n typeof (item as any).status_entry_id === 'string'\n ? (item as any).status_entry_id\n : typeof (item as any).statusEntryId === 'string'\n ? (item as any).statusEntryId\n : null,\n statusLabel:\n typeof (item as any).status_label === 'string'\n ? (item as any).status_label\n : typeof (item as any).statusLabel === 'string'\n ? (item as any).statusLabel\n : null,\n amount: normalizeNumber(item.amount),\n currencyCode:\n typeof item.currency_code === 'string'\n ? item.currency_code\n : typeof currencyCode === 'string'\n ? currencyCode\n : null,\n receivedAt: typeof item.received_at === 'string' ? item.received_at : null,\n createdAt: typeof item.created_at === 'string' ? item.created_at : null,\n customValues: Object.keys(customValues).length ? customValues : null,\n customFieldSetId:\n typeof (item as any)?.custom_field_set_id === 'string'\n ? (item as any).custom_field_set_id\n : typeof (item as any)?.customFieldSetId === 'string'\n ? (item as any).customFieldSetId\n : null,\n }\n return [record]\n })\n setPayments(mapped)\n onPaymentsChangeRef.current?.(mapped)\n } else {\n setPayments([])\n onPaymentsChangeRef.current?.([])\n }\n } catch (err) {\n logger.error('sales.payments.list', { err })\n setError(t('sales.documents.payments.errorLoad', 'Failed to load payments.'))\n onPaymentsChangeRef.current?.([])\n } finally {\n setLoading(false)\n }\n }, [currencyCode, orderId, t])\n\n React.useEffect(() => {\n void loadPayments()\n }, [loadPayments])\n\n const openCreate = React.useCallback(() => {\n setEditingPayment(null)\n setDialogOpen(true)\n }, [])\n\n const handleDialogChange = React.useCallback((nextOpen: boolean) => {\n setDialogOpen(nextOpen)\n if (!nextOpen) {\n setEditingPayment(null)\n }\n }, [])\n\n const openEditPayment = React.useCallback(\n (record: PaymentRow) => {\n setEditingPayment({\n id: record.id,\n updatedAt: record.updatedAt ?? null,\n amount: record.amount ?? '',\n paymentMethodId: record.paymentMethodId ?? '',\n paymentReference: record.paymentReference ?? '',\n receivedAt: record.receivedAt ? record.receivedAt.slice(0, 10) : '',\n currencyCode: record.currencyCode ?? currencyCode ?? null,\n statusEntryId: record.statusEntryId ?? null,\n customValues: record.customValues ?? null,\n customFieldSetId: record.customFieldSetId ?? null,\n })\n setDialogOpen(true)\n },\n [currencyCode]\n )\n\n const handlePaymentSaved = React.useCallback(\n async (_totals?: PaymentTotals | null) => {\n onTotalsChange?.()\n await loadPayments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n handleDialogChange(false)\n },\n [handleDialogChange, loadPayments, onTotalsChange, orderId]\n )\n\n const handleDelete = React.useCallback(\n async (row: PaymentRow) => {\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap A), so\n // send the order's `updated_at`, not the payment row's.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n deleteCrud<{ orderTotals?: PaymentTotals | null }>('sales/payments', {\n body: {\n id: row.id,\n orderId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t('sales.documents.payments.errorDelete', 'Failed to delete payment.'),\n })\n )\n if (result.ok) {\n onTotalsChange?.()\n flash(t('sales.documents.payments.deleted', 'Payment deleted.'), 'success')\n await loadPayments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadPayments())) {\n return\n }\n logger.error('sales.payments.delete', { err })\n flash(t('sales.documents.payments.errorDelete', 'Failed to delete payment.'), 'error')\n }\n },\n [documentUpdatedAt, loadPayments, onTotalsChange, orderId, resolvedOrganizationId, resolvedTenantId, t]\n )\n\n React.useEffect(() => {\n if (!onActionChange) return\n onActionChange({\n label: addActionLabel,\n onClick: openCreate,\n disabled: false,\n })\n return () => onActionChange(null)\n }, [addActionLabel, onActionChange, openCreate])\n\n const columns = React.useMemo<ColumnDef<PaymentRow>[]>(\n () => [\n {\n accessorKey: 'paymentReference',\n header: t('sales.documents.payments.reference', 'Reference'),\n cell: ({ row }) => row.original.paymentReference || '\u2014',\n },\n {\n accessorKey: 'paymentMethodName',\n header: t('sales.documents.payments.method', 'Method'),\n cell: ({ row }) => row.original.paymentMethodName ?? '\u2014',\n },\n {\n // Injected columns are placed against `ColumnDef.id` before the table is\n // built, so an accessor-derived id is not yet available: the gateway\n // status widget anchors on this explicit id.\n id: 'status',\n accessorKey: 'status',\n header: t('sales.documents.payments.status', 'Status'),\n cell: ({ row }) => row.original.statusLabel ?? row.original.status ?? '\u2014',\n },\n {\n accessorKey: 'amount',\n header: t('sales.documents.payments.amount', 'Amount'),\n cell: ({ row }) => formatMoney(row.original.amount, row.original.currencyCode ?? currencyCode, locale),\n },\n {\n accessorKey: 'receivedAt',\n header: t('sales.documents.payments.receivedAt', 'Received'),\n // `receivedAt` is written from a date input (`PaymentDialog`), coerced with\n // `z.coerce.date()` and stored as UTC midnight, so its day must be read in UTC.\n // Reading it locally names the previous day west of UTC \u2014 and disagrees with the\n // Edit dialog, which seeds from `receivedAt.slice(0, 10)`, i.e. the UTC day.\n cell: ({ row }) => formatDisplayDate(toUtcDateInputValue(row.original.receivedAt), locale) ?? '\u2014',\n },\n {\n accessorKey: 'createdAt',\n header: t('sales.documents.payments.createdAt', 'Created'),\n cell: ({ row }) => formatDisplayDateTime(row.original.createdAt, locale) ?? '\u2014',\n meta: {\n tooltipContent: (row: PaymentRow) => formatDisplayDateTime(row.createdAt, locale) ?? undefined,\n },\n },\n {\n id: 'actions',\n header: '',\n cell: ({ row }) => {\n return (\n <RowActions\n items={[\n { id: 'edit', label: editActionLabel, onSelect: () => openEditPayment(row.original) },\n {\n id: 'delete',\n label: deleteActionLabel,\n destructive: true,\n onSelect: () => void handleDelete(row.original),\n },\n ]}\n />\n )\n },\n },\n ],\n [currencyCode, deleteActionLabel, editActionLabel, handleDelete, locale, openEditPayment, t]\n )\n\n if (loading) {\n return (\n <LoadingMessage\n label={t('sales.documents.payments.loading', 'Loading payments\u2026')}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n )\n }\n\n if (error) {\n return (\n <ErrorMessage\n label={error}\n action={\n <Button variant=\"outline\" size=\"sm\" onClick={() => void loadPayments()}>\n {t('sales.documents.payments.retry', 'Retry')}\n </Button>\n }\n />\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {payments.length ? (\n <DataTable<PaymentRow>\n columns={columns}\n data={payments}\n onRowClick={openEditPayment}\n extensionTableId={extensionPoints.hosts.paymentsTable.tableId}\n />\n ) : (\n <TabEmptyState\n title={t('sales.documents.payments.emptyTitle', 'No payments yet.')}\n description={t(\n 'sales.documents.payments.emptyDescription',\n 'Track received payments to keep outstanding balances up to date.'\n )}\n action={{\n label: addActionLabel,\n onClick: openCreate,\n icon: <Plus className=\"h-4 w-4\" aria-hidden />,\n disabled: loading,\n }}\n />\n )}\n\n <PaymentDialog\n open={dialogOpen}\n onOpenChange={handleDialogChange}\n mode={editingPayment ? 'edit' : 'create'}\n payment={editingPayment}\n currencyCode={editingPayment?.currencyCode ?? currencyCode}\n orderId={orderId}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n documentUpdatedAt={documentUpdatedAt ?? null}\n onSaved={handlePaymentSaved}\n />\n </div>\n )\n}\n"],
|
|
5
|
-
"mappings": ";AA2TY,cAyCR,YAzCQ;AAzTZ,YAAY,WAAW;AAEvB,SAAS,iBAAiB;AAC1B,SAAS,gBAAgB,cAAc,qBAAqB;AAC5D,SAAS,SAAS,mCAAmC;AACrD,SAAS,iCAAiC;AAC1C,SAAS,kBAAkB;AAC3B,SAAS,4BAA4B,wBAAwB;AAE7D,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,SAAS,mBAAmB,uBAAuB,2BAA2B;AAC9E,SAAS,aAAa;AACtB,SAAS,kCAAkC;AAC3C,SAAS,MAAM,iBAAiB;AAChC,SAAS,sCAAsC;AAC/C,SAAS,uBAAuB;AAChC,SAAS,qBAA+D;AACxE,SAAS,gCAAgC;AACzC,SAAS,YAAY;AACrB,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,OAAO;AA8BnC,SAAS,gBAAgB,OAAwB;AAC/C,MAAI,OAAO,UAAU,YAAY,OAAO,SAAS,KAAK,EAAG,QAAO;AAChE,MAAI,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,QAAQ;AACpD,UAAM,SAAS,OAAO,KAAK;AAC3B,QAAI,CAAC,OAAO,MAAM,MAAM,EAAG,QAAO;AAAA,EACpC;AACA,SAAO;AACT;AAEA,SAAS,YAAY,OAAe,UAAqC,QAAyB;AAChG,MAAI,CAAC,YAAY,SAAS,KAAK,EAAE,WAAW,EAAG,QAAO,MAAM,QAAQ,CAAC;AACrE,MAAI;AACF,WAAO,IAAI,KAAK,aAAa,QAAQ,EAAE,OAAO,YAAY,SAAS,CAAC,EAAE,OAAO,KAAK;AAAA,EACpF,QAAQ;AACN,WAAO,GAAG,SAAS,YAAY,CAAC,IAAI,MAAM,QAAQ,CAAC,CAAC;AAAA,EACtD;AACF;AAEO,SAAS,6BAA6B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAsC;AACpC,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,EAAE,gBAAgB,SAAS,IAAI,2BAA2B;AAChE,QAAM,yBAAyB,gBAAgB,kBAAkB;AACjE,QAAM,mBAAmB,mBAAmB,YAAY;AACxD,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAuB,CAAC,CAAC;AAC/D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAiC,IAAI;AACvF,QAAM,sBAAsB,MAAM,OAAgC,gBAAgB;AAElF,QAAM,UAAU,MAAM;AACpB,wBAAoB,UAAU;AAAA,EAChC,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,iBAAiB,EAAE,gCAAgC,aAAa;AACtE,QAAM,kBAAkB,EAAE,iCAAiC,cAAc;AACzE,QAAM,oBAAoB,EAAE,mCAAmC,gBAAgB;AAE/E,QAAM,eAAe,MAAM,YAAY,YAAY;AACjD,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,KAAK,UAAU,OAAO,QAAQ,CAAC;AAC1E,YAAM,WAAW,MAAM;AAAA,QACrB,uBAAuB,OAAO,SAAS,CAAC;AAAA,QACxC;AAAA,QACA,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,EAAE;AAAA,MAC5B;AACA,UAAI,SAAS,MAAM,MAAM,QAAQ,SAAS,QAAQ,KAAK,GAAG;AACxD,cAAM,SAAS,SAAS,OAAO,MAAM,QAAoB,CAAC,SAAS;AACjE,cAAI,OAAO,KAAK,OAAO,SAAU,QAAO,CAAC;AACzC,gBAAM,eACJ,QAAQ,OAAO,SAAS,WACpB,yBAAyB,IAA+B,IACxD,CAAC;AACP,gBAAM,SAAqB;AAAA,YACzB,IAAI,KAAK;AAAA,YACT,WAAW,iBAAiB,IAAI;AAAA,YAChC,kBAAkB,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB;AAAA,YACxF,iBAAiB,OAAO,KAAK,sBAAsB,WAAW,KAAK,oBAAoB;AAAA,YACvF,mBACE,OAAO,KAAK,wBAAwB,WAChC,KAAK,sBACL,OAAO,KAAK,wBAAwB,WAClC,KAAK,sBACL;AAAA,YACR,QAAQ,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,YACxD,eACE,OAAQ,KAAa,oBAAoB,WACpC,KAAa,kBACd,OAAQ,KAAa,kBAAkB,WACpC,KAAa,gBACd;AAAA,YACR,aACE,OAAQ,KAAa,iBAAiB,WACjC,KAAa,eACd,OAAQ,KAAa,gBAAgB,WAClC,KAAa,cACd;AAAA,YACR,QAAQ,gBAAgB,KAAK,MAAM;AAAA,YACnC,cACE,OAAO,KAAK,kBAAkB,WAC1B,KAAK,gBACL,OAAO,iBAAiB,WACtB,eACA;AAAA,YACR,YAAY,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAAA,YACtE,WAAW,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;AAAA,YACnE,cAAc,OAAO,KAAK,YAAY,EAAE,SAAS,eAAe;AAAA,YAChE,kBACE,OAAQ,MAAc,wBAAwB,WACzC,KAAa,sBACd,OAAQ,MAAc,qBAAqB,WACxC,KAAa,mBACd;AAAA,UACV;AACA,iBAAO,CAAC,MAAM;AAAA,QAChB,CAAC;AACD,oBAAY,MAAM;AAClB,4BAAoB,UAAU,MAAM;AAAA,MACtC,OAAO;AACL,oBAAY,CAAC,CAAC;AACd,4BAAoB,UAAU,CAAC,CAAC;AAAA,MAClC;AAAA,IACF,SAAS,KAAK;AACZ,aAAO,MAAM,uBAAuB,EAAE,IAAI,CAAC;AAC3C,eAAS,EAAE,sCAAsC,0BAA0B,CAAC;AAC5E,0BAAoB,UAAU,CAAC,CAAC;AAAA,IAClC,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF,GAAG,CAAC,cAAc,SAAS,CAAC,CAAC;AAE7B,QAAM,UAAU,MAAM;AACpB,SAAK,aAAa;AAAA,EACpB,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,sBAAkB,IAAI;AACtB,kBAAc,IAAI;AAAA,EACpB,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,MAAM,YAAY,CAAC,aAAsB;AAClE,kBAAc,QAAQ;AACtB,QAAI,CAAC,UAAU;AACb,wBAAkB,IAAI;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,WAAuB;AACtB,wBAAkB;AAAA,QAChB,IAAI,OAAO;AAAA,QACX,WAAW,OAAO,aAAa;AAAA,QAC/B,QAAQ,OAAO,UAAU;AAAA,QACzB,iBAAiB,OAAO,mBAAmB;AAAA,QAC3C,kBAAkB,OAAO,oBAAoB;AAAA,QAC7C,YAAY,OAAO,aAAa,OAAO,WAAW,MAAM,GAAG,EAAE,IAAI;AAAA,QACjE,cAAc,OAAO,gBAAgB,gBAAgB;AAAA,QACrD,eAAe,OAAO,iBAAiB;AAAA,QACvC,cAAc,OAAO,gBAAgB;AAAA,QACrC,kBAAkB,OAAO,oBAAoB;AAAA,MAC/C,CAAC;AACD,oBAAc,IAAI;AAAA,IACpB;AAAA,IACA,CAAC,YAAY;AAAA,EACf;AAEA,QAAM,qBAAqB,MAAM;AAAA,IAC/B,OAAO,YAAmC;AACxC,uBAAiB;AACjB,YAAM,aAAa;AACnB,qCAA+B,EAAE,YAAY,SAAS,MAAM,QAAQ,CAAC;AACrE,yBAAmB,KAAK;AAAA,IAC1B;AAAA,IACA,CAAC,oBAAoB,cAAc,gBAAgB,OAAO;AAAA,EAC5D;AAEA,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,QAAoB;AACzB,UAAI;AACF,cAAM,SAAS,MAAM;AAAA;AAAA;AAAA,UAGnB,0BAA0B,qBAAqB,MAAS;AAAA,UACxD,MACE,WAAmD,kBAAkB;AAAA,YACnE,MAAM;AAAA,cACJ,IAAI,IAAI;AAAA,cACR;AAAA,cACA,gBAAgB,0BAA0B;AAAA,cAC1C,UAAU,oBAAoB;AAAA,YAChC;AAAA,YACA,cAAc,EAAE,wCAAwC,2BAA2B;AAAA,UACrF,CAAC;AAAA,QACL;AACA,YAAI,OAAO,IAAI;AACb,2BAAiB;AACjB,gBAAM,EAAE,oCAAoC,kBAAkB,GAAG,SAAS;AAC1E,gBAAM,aAAa;AACnB,yCAA+B,EAAE,YAAY,SAAS,MAAM,QAAQ,CAAC;AAAA,QACvE;AAAA,MACF,SAAS,KAAK;AACZ,YAAI,2BAA2B,KAAK,GAAG,MAAM,KAAK,aAAa,CAAC,GAAG;AACjE;AAAA,QACF;AACA,eAAO,MAAM,yBAAyB,EAAE,IAAI,CAAC;AAC7C,cAAM,EAAE,wCAAwC,2BAA2B,GAAG,OAAO;AAAA,MACvF;AAAA,IACF;AAAA,IACA,CAAC,mBAAmB,cAAc,gBAAgB,SAAS,wBAAwB,kBAAkB,CAAC;AAAA,EACxG;AAEA,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,eAAgB;AACrB,mBAAe;AAAA,MACb,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC;AACD,WAAO,MAAM,eAAe,IAAI;AAAA,EAClC,GAAG,CAAC,gBAAgB,gBAAgB,UAAU,CAAC;AAE/C,QAAM,UAAU,MAAM;AAAA,IACpB,MAAM;AAAA,MACJ;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,sCAAsC,WAAW;AAAA,QAC3D,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,oBAAoB;AAAA,MACtD;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,mCAAmC,QAAQ;AAAA,QACrD,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,qBAAqB;AAAA,MACvD;AAAA,MACA;AAAA;AAAA;AAAA;AAAA,QAIE,IAAI;AAAA,QACJ,aAAa;AAAA,QACb,QAAQ,EAAE,mCAAmC,QAAQ;AAAA,QACrD,MAAM,CAAC,EAAE,IAAI,MAAM,IAAI,SAAS,eAAe,IAAI,SAAS,UAAU;AAAA,MACxE;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,mCAAmC,QAAQ;AAAA,QACrD,MAAM,CAAC,EAAE,IAAI,MAAM,YAAY,IAAI,SAAS,QAAQ,IAAI,SAAS,gBAAgB,cAAc,MAAM;AAAA,MACvG;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,uCAAuC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA,QAK3D,MAAM,CAAC,EAAE,IAAI,MAAM,kBAAkB,oBAAoB,IAAI,SAAS,UAAU,GAAG,MAAM,KAAK;AAAA,MAChG;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,QAAQ,EAAE,sCAAsC,SAAS;AAAA,QACzD,MAAM,CAAC,EAAE,IAAI,MAAM,sBAAsB,IAAI,SAAS,WAAW,MAAM,KAAK;AAAA,QAC5E,MAAM;AAAA,UACJ,gBAAgB,CAAC,QAAoB,sBAAsB,IAAI,WAAW,MAAM,KAAK;AAAA,QACvF;AAAA,MACF;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,QAAQ;AAAA,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { LoadingMessage, ErrorMessage, TabEmptyState } from '@open-mercato/ui/backend/detail'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { handleSectionMutationError, readRowUpdatedAt } from './optimisticLock'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { formatDisplayDate, formatDisplayDateTime, toUtcDateInputValue } from '@open-mercato/ui/primitives/date-format'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useOrganizationScopeDetail } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, useLocale } from '@open-mercato/shared/lib/i18n/context'\nimport { emitSalesDocumentTotalsRefresh } from '@open-mercato/core/modules/sales/lib/frontend/documentTotalsEvents'\nimport { extensionPoints } from '@open-mercato/core/modules/sales/extension-points'\nimport { PaymentDialog, type PaymentFormData, type PaymentTotals } from './PaymentDialog'\nimport { extractCustomFieldValues } from './customFieldHelpers'\nimport { Plus } from 'lucide-react'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('sales')\n\ntype PaymentRow = {\n id: string\n updatedAt: string | null\n paymentReference: string | null\n paymentMethodId: string | null\n paymentMethodName: string | null\n status: string | null\n statusEntryId: string | null\n statusLabel: string | null\n amount: number\n currencyCode: string | null\n receivedAt: string | null\n createdAt: string | null\n customValues?: Record<string, unknown> | null\n customFieldSetId?: string | null\n}\n\ntype SalesDocumentPaymentsSectionProps = {\n orderId: string\n currencyCode: string | null | undefined\n organizationId?: string | null\n tenantId?: string | null\n documentUpdatedAt?: string | null\n onActionChange?: (action: SectionAction | null) => void\n onTotalsChange?: () => void\n onPaymentsChange?: (payments: PaymentRow[]) => void\n}\n\nfunction normalizeNumber(value: unknown): number {\n if (typeof value === 'number' && Number.isFinite(value)) return value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n if (!Number.isNaN(parsed)) return parsed\n }\n return 0\n}\n\nfunction formatMoney(value: number, currency: string | null | undefined, locale?: string): string {\n if (!currency || currency.trim().length !== 3) return value.toFixed(2)\n try {\n return new Intl.NumberFormat(locale, { style: 'currency', currency }).format(value)\n } catch {\n return `${currency.toUpperCase()} ${value.toFixed(2)}`\n }\n}\n\nexport function SalesDocumentPaymentsSection({\n orderId,\n currencyCode,\n organizationId: orgFromProps,\n tenantId: tenantFromProps,\n documentUpdatedAt,\n onActionChange,\n onTotalsChange,\n onPaymentsChange,\n}: SalesDocumentPaymentsSectionProps) {\n const t = useT()\n const locale = useLocale()\n const { organizationId, tenantId } = useOrganizationScopeDetail()\n const resolvedOrganizationId = orgFromProps ?? organizationId ?? null\n const resolvedTenantId = tenantFromProps ?? tenantId ?? null\n const [payments, setPayments] = React.useState<PaymentRow[]>([])\n const [loading, setLoading] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n const [dialogOpen, setDialogOpen] = React.useState(false)\n const [editingPayment, setEditingPayment] = React.useState<PaymentFormData | null>(null)\n const onPaymentsChangeRef = React.useRef<typeof onPaymentsChange>(onPaymentsChange)\n\n React.useEffect(() => {\n onPaymentsChangeRef.current = onPaymentsChange\n }, [onPaymentsChange])\n\n const addActionLabel = t('sales.documents.payments.add', 'Add payment')\n const editActionLabel = t('sales.documents.payments.edit', 'Edit payment')\n const deleteActionLabel = t('sales.documents.payments.delete', 'Delete payment')\n\n const loadPayments = React.useCallback(async () => {\n setLoading(true)\n setError(null)\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '100', orderId })\n const response = await apiCall<{ items?: Array<Record<string, unknown>> }>(\n `/api/sales/payments?${params.toString()}`,\n undefined,\n { fallback: { items: [] } }\n )\n if (response.ok && Array.isArray(response.result?.items)) {\n const mapped = response.result.items.flatMap<PaymentRow>((item) => {\n if (typeof item.id !== 'string') return []\n const customValues =\n item && typeof item === 'object'\n ? extractCustomFieldValues(item as Record<string, unknown>)\n : {}\n const record: PaymentRow = {\n id: item.id,\n updatedAt: readRowUpdatedAt(item),\n paymentReference: typeof item.payment_reference === 'string' ? item.payment_reference : null,\n paymentMethodId: typeof item.payment_method_id === 'string' ? item.payment_method_id : null,\n paymentMethodName:\n typeof item.payment_method_name === 'string'\n ? item.payment_method_name\n : typeof item.payment_method_code === 'string'\n ? item.payment_method_code\n : null,\n status: typeof item.status === 'string' ? item.status : null,\n statusEntryId:\n typeof (item as any).status_entry_id === 'string'\n ? (item as any).status_entry_id\n : typeof (item as any).statusEntryId === 'string'\n ? (item as any).statusEntryId\n : null,\n statusLabel:\n typeof (item as any).status_label === 'string'\n ? (item as any).status_label\n : typeof (item as any).statusLabel === 'string'\n ? (item as any).statusLabel\n : null,\n amount: normalizeNumber(item.amount),\n currencyCode:\n typeof item.currency_code === 'string'\n ? item.currency_code\n : typeof currencyCode === 'string'\n ? currencyCode\n : null,\n receivedAt: typeof item.received_at === 'string' ? item.received_at : null,\n createdAt: typeof item.created_at === 'string' ? item.created_at : null,\n customValues: Object.keys(customValues).length ? customValues : null,\n customFieldSetId:\n typeof (item as any)?.custom_field_set_id === 'string'\n ? (item as any).custom_field_set_id\n : typeof (item as any)?.customFieldSetId === 'string'\n ? (item as any).customFieldSetId\n : null,\n }\n return [record]\n })\n setPayments(mapped)\n onPaymentsChangeRef.current?.(mapped)\n } else {\n setPayments([])\n onPaymentsChangeRef.current?.([])\n }\n } catch (err) {\n logger.error('sales.payments.list', { err })\n setError(t('sales.documents.payments.errorLoad', 'Failed to load payments.'))\n onPaymentsChangeRef.current?.([])\n } finally {\n setLoading(false)\n }\n }, [currencyCode, orderId, t])\n\n React.useEffect(() => {\n void loadPayments()\n }, [loadPayments])\n\n const openCreate = React.useCallback(() => {\n setEditingPayment(null)\n setDialogOpen(true)\n }, [])\n\n const handleDialogChange = React.useCallback((nextOpen: boolean) => {\n setDialogOpen(nextOpen)\n if (!nextOpen) {\n setEditingPayment(null)\n }\n }, [])\n\n const openEditPayment = React.useCallback(\n (record: PaymentRow) => {\n setEditingPayment({\n id: record.id,\n updatedAt: record.updatedAt ?? null,\n amount: record.amount ?? '',\n paymentMethodId: record.paymentMethodId ?? '',\n paymentReference: record.paymentReference ?? '',\n receivedAt: record.receivedAt ? record.receivedAt.slice(0, 10) : '',\n currencyCode: record.currencyCode ?? currencyCode ?? null,\n statusEntryId: record.statusEntryId ?? null,\n customValues: record.customValues ?? null,\n customFieldSetId: record.customFieldSetId ?? null,\n })\n setDialogOpen(true)\n },\n [currencyCode]\n )\n\n const handlePaymentSaved = React.useCallback(\n async (_totals?: PaymentTotals | null) => {\n onTotalsChange?.()\n await loadPayments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n handleDialogChange(false)\n },\n [handleDialogChange, loadPayments, onTotalsChange, orderId]\n )\n\n const handleDelete = React.useCallback(\n async (row: PaymentRow) => {\n try {\n const result = await withScopedApiRequestHeaders(\n // The server guards the PARENT order's aggregate version (Gap A), so\n // send the order's `updated_at`, not the payment row's.\n buildOptimisticLockHeader(documentUpdatedAt ?? undefined),\n () =>\n deleteCrud<{ orderTotals?: PaymentTotals | null }>('sales/payments', {\n body: {\n id: row.id,\n orderId,\n organizationId: resolvedOrganizationId ?? undefined,\n tenantId: resolvedTenantId ?? undefined,\n },\n errorMessage: t('sales.documents.payments.errorDelete', 'Failed to delete payment.'),\n })\n )\n if (result.ok) {\n onTotalsChange?.()\n flash(t('sales.documents.payments.deleted', 'Payment deleted.'), 'success')\n await loadPayments()\n emitSalesDocumentTotalsRefresh({ documentId: orderId, kind: 'order' })\n }\n } catch (err) {\n if (handleSectionMutationError(err, t, () => void loadPayments())) {\n return\n }\n logger.error('sales.payments.delete', { err })\n flash(t('sales.documents.payments.errorDelete', 'Failed to delete payment.'), 'error')\n }\n },\n [documentUpdatedAt, loadPayments, onTotalsChange, orderId, resolvedOrganizationId, resolvedTenantId, t]\n )\n\n React.useEffect(() => {\n if (!onActionChange) return\n onActionChange({\n label: addActionLabel,\n onClick: openCreate,\n disabled: false,\n })\n return () => onActionChange(null)\n }, [addActionLabel, onActionChange, openCreate])\n\n const columns = React.useMemo<ColumnDef<PaymentRow>[]>(\n () => [\n {\n accessorKey: 'paymentReference',\n header: t('sales.documents.payments.reference', 'Reference'),\n cell: ({ row }) => row.original.paymentReference || '\u2014',\n },\n {\n accessorKey: 'paymentMethodName',\n header: t('sales.documents.payments.method', 'Method'),\n cell: ({ row }) => row.original.paymentMethodName ?? '\u2014',\n },\n {\n // Injected columns are placed against `ColumnDef.id` before the table is\n // built, so an accessor-derived id is not yet available: the gateway\n // status widget anchors on this explicit id.\n id: 'status',\n accessorKey: 'status',\n header: t('sales.documents.payments.status', 'Status'),\n cell: ({ row }) => row.original.statusLabel ?? row.original.status ?? '\u2014',\n },\n {\n accessorKey: 'amount',\n header: t('sales.documents.payments.amount', 'Amount'),\n cell: ({ row }) => formatMoney(row.original.amount, row.original.currencyCode ?? currencyCode, locale),\n },\n {\n accessorKey: 'receivedAt',\n header: t('sales.documents.payments.receivedAt', 'Received'),\n // `receivedAt` is written from a date input (`PaymentDialog`), coerced with\n // `z.coerce.date()` and stored as UTC midnight, so its day must be read in UTC.\n // Reading it locally names the previous day west of UTC \u2014 and disagrees with the\n // Edit dialog, which seeds from `receivedAt.slice(0, 10)`, i.e. the UTC day.\n cell: ({ row }) => formatDisplayDate(toUtcDateInputValue(row.original.receivedAt), locale) ?? '\u2014',\n },\n {\n accessorKey: 'createdAt',\n header: t('sales.documents.payments.createdAt', 'Created'),\n cell: ({ row }) => formatDisplayDateTime(row.original.createdAt, locale) ?? '\u2014',\n meta: {\n tooltipContent: (row: PaymentRow) => formatDisplayDateTime(row.createdAt, locale) ?? undefined,\n },\n },\n {\n id: 'actions',\n header: t('ui.dataTable.actionsColumn', 'Actions'),\n cell: ({ row }) => {\n return (\n <RowActions\n items={[\n { id: 'edit', label: editActionLabel, onSelect: () => openEditPayment(row.original) },\n {\n id: 'delete',\n label: deleteActionLabel,\n destructive: true,\n onSelect: () => void handleDelete(row.original),\n },\n ]}\n />\n )\n },\n },\n ],\n [currencyCode, deleteActionLabel, editActionLabel, handleDelete, locale, openEditPayment, t]\n )\n\n if (loading) {\n return (\n <LoadingMessage\n label={t('sales.documents.payments.loading', 'Loading payments\u2026')}\n className=\"border-0 bg-transparent p-0 py-8 justify-center\"\n />\n )\n }\n\n if (error) {\n return (\n <ErrorMessage\n label={error}\n action={\n <Button variant=\"outline\" size=\"sm\" onClick={() => void loadPayments()}>\n {t('sales.documents.payments.retry', 'Retry')}\n </Button>\n }\n />\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {payments.length ? (\n <DataTable<PaymentRow>\n columns={columns}\n data={payments}\n onRowClick={openEditPayment}\n extensionTableId={extensionPoints.hosts.paymentsTable.tableId}\n />\n ) : (\n <TabEmptyState\n title={t('sales.documents.payments.emptyTitle', 'No payments yet.')}\n description={t(\n 'sales.documents.payments.emptyDescription',\n 'Track received payments to keep outstanding balances up to date.'\n )}\n action={{\n label: addActionLabel,\n onClick: openCreate,\n icon: <Plus className=\"h-4 w-4\" aria-hidden />,\n disabled: loading,\n }}\n />\n )}\n\n <PaymentDialog\n open={dialogOpen}\n onOpenChange={handleDialogChange}\n mode={editingPayment ? 'edit' : 'create'}\n payment={editingPayment}\n currencyCode={editingPayment?.currencyCode ?? currencyCode}\n orderId={orderId}\n organizationId={resolvedOrganizationId}\n tenantId={resolvedTenantId}\n documentUpdatedAt={documentUpdatedAt ?? null}\n onSaved={handlePaymentSaved}\n />\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/core",
|
|
3
|
-
"version": "0.10.1-develop.
|
|
3
|
+
"version": "0.10.1-develop.7865.1.9a16aa6194",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -266,16 +266,16 @@
|
|
|
266
266
|
"zod": "^4.6.6"
|
|
267
267
|
},
|
|
268
268
|
"peerDependencies": {
|
|
269
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
270
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
271
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
269
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7865.1.9a16aa6194",
|
|
270
|
+
"@open-mercato/shared": "0.10.1-develop.7865.1.9a16aa6194",
|
|
271
|
+
"@open-mercato/ui": "0.10.1-develop.7865.1.9a16aa6194",
|
|
272
272
|
"react": "^19.0.0",
|
|
273
273
|
"react-dom": "^19.0.0"
|
|
274
274
|
},
|
|
275
275
|
"devDependencies": {
|
|
276
|
-
"@open-mercato/ai-assistant": "0.10.1-develop.
|
|
277
|
-
"@open-mercato/shared": "0.10.1-develop.
|
|
278
|
-
"@open-mercato/ui": "0.10.1-develop.
|
|
276
|
+
"@open-mercato/ai-assistant": "0.10.1-develop.7865.1.9a16aa6194",
|
|
277
|
+
"@open-mercato/shared": "0.10.1-develop.7865.1.9a16aa6194",
|
|
278
|
+
"@open-mercato/ui": "0.10.1-develop.7865.1.9a16aa6194",
|
|
279
279
|
"@testing-library/dom": "^10.4.1",
|
|
280
280
|
"@testing-library/jest-dom": "^7.0.1",
|
|
281
281
|
"@testing-library/react": "^16.3.3",
|
|
@@ -15,7 +15,6 @@ import type { ActionLog } from '@open-mercato/core/modules/audit_logs/data/entit
|
|
|
15
15
|
import { z } from 'zod'
|
|
16
16
|
import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
|
|
17
17
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
18
|
-
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
19
18
|
import { getCommandInterceptorHttpRejection } from '@open-mercato/shared/lib/commands/errors'
|
|
20
19
|
import { authorizeAuditReplayWithEntityManager } from '@open-mercato/core/modules/audit_logs/lib/replayAuthorization'
|
|
21
20
|
import {
|