@open-mercato/core 0.6.1-develop.3069.d40b4417a9 → 0.6.1-develop.3090.06ab462170

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 (84) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/modules/audit_logs/services/accessLogService.js +13 -0
  3. package/dist/modules/audit_logs/services/accessLogService.js.map +3 -3
  4. package/dist/modules/audit_logs/services/actionLogService.js +6 -5
  5. package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
  6. package/dist/modules/customers/api/activities/route.js +1 -52
  7. package/dist/modules/customers/api/activities/route.js.map +2 -2
  8. package/dist/modules/customers/api/interactions/counts/route.js +2 -1
  9. package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
  10. package/dist/modules/customers/api/interactions/route.js +21 -1
  11. package/dist/modules/customers/api/interactions/route.js.map +2 -2
  12. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +7 -3
  13. package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
  14. package/dist/modules/customers/backend/customers/deals/[id]/page.js +5 -1
  15. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  16. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +7 -3
  17. package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
  18. package/dist/modules/customers/components/detail/ActivitiesCard.js +62 -6
  19. package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
  20. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +21 -6
  21. package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
  22. package/dist/modules/customers/components/detail/ActivitiesSection.js +37 -5
  23. package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
  24. package/dist/modules/customers/components/detail/ActivityCard.js +69 -17
  25. package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
  26. package/dist/modules/customers/components/detail/ActivityHistorySection.js +94 -34
  27. package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +2 -2
  28. package/dist/modules/customers/components/detail/ActivityLogTab.js +3 -1
  29. package/dist/modules/customers/components/detail/ActivityLogTab.js.map +2 -2
  30. package/dist/modules/customers/components/detail/ActivityTimeline.js +41 -8
  31. package/dist/modules/customers/components/detail/ActivityTimeline.js.map +2 -2
  32. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +19 -6
  33. package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +2 -2
  34. package/dist/modules/customers/components/detail/ActivityTypeSelector.js +4 -3
  35. package/dist/modules/customers/components/detail/ActivityTypeSelector.js.map +2 -2
  36. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +80 -12
  37. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  38. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +65 -10
  39. package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +2 -2
  40. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +10 -5
  41. package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
  42. package/dist/modules/customers/data/validators.js +74 -2
  43. package/dist/modules/customers/data/validators.js.map +2 -2
  44. package/dist/modules/customers/lib/legacyActivityBridge.js +61 -0
  45. package/dist/modules/customers/lib/legacyActivityBridge.js.map +7 -0
  46. package/dist/modules/integrations/lib/credentials-service.js +12 -1
  47. package/dist/modules/integrations/lib/credentials-service.js.map +2 -2
  48. package/dist/modules/messages/commands/actions.js +29 -14
  49. package/dist/modules/messages/commands/actions.js.map +2 -2
  50. package/dist/modules/messages/lib/actions.js +24 -4
  51. package/dist/modules/messages/lib/actions.js.map +2 -2
  52. package/dist/modules/sales/api/documents/factory.js +49 -36
  53. package/dist/modules/sales/api/documents/factory.js.map +2 -2
  54. package/package.json +5 -5
  55. package/src/modules/audit_logs/services/accessLogService.ts +20 -0
  56. package/src/modules/audit_logs/services/actionLogService.ts +13 -5
  57. package/src/modules/customers/api/activities/route.ts +1 -76
  58. package/src/modules/customers/api/interactions/counts/route.ts +2 -1
  59. package/src/modules/customers/api/interactions/route.ts +28 -1
  60. package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +13 -3
  61. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +14 -2
  62. package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +13 -3
  63. package/src/modules/customers/components/detail/ActivitiesCard.tsx +92 -5
  64. package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +38 -6
  65. package/src/modules/customers/components/detail/ActivitiesSection.tsx +37 -3
  66. package/src/modules/customers/components/detail/ActivityCard.tsx +79 -14
  67. package/src/modules/customers/components/detail/ActivityHistorySection.tsx +102 -33
  68. package/src/modules/customers/components/detail/ActivityLogTab.tsx +7 -1
  69. package/src/modules/customers/components/detail/ActivityTimeline.tsx +39 -5
  70. package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +29 -7
  71. package/src/modules/customers/components/detail/ActivityTypeSelector.tsx +3 -2
  72. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +96 -13
  73. package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +50 -4
  74. package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +21 -5
  75. package/src/modules/customers/data/validators.ts +85 -2
  76. package/src/modules/customers/i18n/de.json +11 -0
  77. package/src/modules/customers/i18n/en.json +11 -0
  78. package/src/modules/customers/i18n/es.json +11 -0
  79. package/src/modules/customers/i18n/pl.json +11 -0
  80. package/src/modules/customers/lib/legacyActivityBridge.ts +106 -0
  81. package/src/modules/integrations/lib/credentials-service.ts +15 -1
  82. package/src/modules/messages/commands/actions.ts +28 -13
  83. package/src/modules/messages/lib/actions.ts +34 -3
  84. package/src/modules/sales/api/documents/factory.ts +55 -38
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/sales/api/documents/factory.ts"],
4
- "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { splitCustomFieldPayload, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { E } from '#generated/entities.ids.generated'\nimport type { SalesOrder, SalesQuote } from '../../data/entities'\nimport { SalesDocumentTagAssignment } from '../../data/entities'\nimport {\n orderCreateSchema,\n quoteCreateSchema,\n} from '../../data/validators'\nimport {\n createPagedListResponseSchema,\n createSalesCrudOpenApi,\n defaultDeleteRequestSchema,\n} from '../openapi'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { documentUpdateSchema } from '../../commands/documents'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { recalculateOrderTotalsForDisplay } from '../../commands/returns'\n\ntype DocumentKind = 'order' | 'quote'\n\ntype DocumentBinding = {\n kind: DocumentKind\n entity: typeof SalesOrder | typeof SalesQuote\n entityId: (typeof E.sales)[keyof typeof E.sales]\n numberField: 'orderNumber' | 'quoteNumber'\n createCommandId: string\n updateCommandId: string\n deleteCommandId: string\n manageFeature: string\n viewFeature: string\n}\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst resolveCustomerName = (snapshot: Record<string, unknown> | null, fallback?: string | null) => {\n if (!snapshot) return fallback ?? null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const contact = snapshot.contact as Record<string, unknown> | undefined\n const displayName = typeof customer?.displayName === 'string' ? customer.displayName : null\n if (displayName) return displayName\n const first = typeof contact?.firstName === 'string' ? contact.firstName : null\n const last = typeof contact?.lastName === 'string' ? contact.lastName : null\n const preferred = typeof contact?.preferredName === 'string' ? contact.preferredName : null\n const parts = [preferred ?? first, last].filter((part) => part && part.trim().length)\n if (parts.length) return parts.join(' ')\n return fallback ?? null\n}\n\nconst resolveCustomerEmail = (snapshot: Record<string, unknown> | null) => {\n if (!snapshot) return null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const primary = typeof customer?.primaryEmail === 'string' ? customer.primaryEmail : null\n return primary ?? null\n}\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n id: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n lineItemCountMin: z.coerce.number().min(0).optional(),\n lineItemCountMax: z.coerce.number().min(0).optional(),\n totalNetMin: z.coerce.number().optional(),\n totalNetMax: z.coerce.number().optional(),\n totalGrossMin: z.coerce.number().optional(),\n totalGrossMax: z.coerce.number().optional(),\n dateFrom: z.string().optional(),\n dateTo: z.string().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype ListQuery = z.infer<typeof listSchema>\n\nfunction buildFilters(query: ListQuery, numberColumn: string, kind: DocumentKind) {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.search && query.search.trim().length > 0) {\n const term = `%${escapeLikePattern(query.search.trim())}%`\n filters[numberColumn] = { $ilike: term }\n }\n if (query.customerId) {\n filters.customer_entity_id = { $eq: query.customerId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n }\n const lineRange: Record<string, number> = {}\n if (typeof query.lineItemCountMin === 'number') lineRange.$gte = query.lineItemCountMin\n if (typeof query.lineItemCountMax === 'number') lineRange.$lte = query.lineItemCountMax\n if (Object.keys(lineRange).length) {\n filters.line_item_count = lineRange\n }\n const netRange: Record<string, number> = {}\n if (typeof query.totalNetMin === 'number') netRange.$gte = query.totalNetMin\n if (typeof query.totalNetMax === 'number') netRange.$lte = query.totalNetMax\n if (Object.keys(netRange).length) {\n filters.grand_total_net_amount = netRange\n }\n const grossRange: Record<string, number> = {}\n if (typeof query.totalGrossMin === 'number') grossRange.$gte = query.totalGrossMin\n if (typeof query.totalGrossMax === 'number') grossRange.$lte = query.totalGrossMax\n if (Object.keys(grossRange).length) {\n filters.grand_total_gross_amount = grossRange\n }\n const dateRange: Record<string, Date> = {}\n if (query.dateFrom) {\n const from = new Date(query.dateFrom)\n if (!Number.isNaN(from.getTime())) dateRange.$gte = from\n }\n if (query.dateTo) {\n const to = new Date(query.dateTo)\n if (!Number.isNaN(to.getTime())) dateRange.$lte = to\n }\n if (Object.keys(dateRange).length) {\n filters.created_at = dateRange\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n if (parseBooleanToken(query.tagIdsEmpty) === true) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n filters['tag_assignments.document_kind'] = { $eq: kind }\n }\n return filters\n}\n\nfunction buildSortMap(numberColumn: string) {\n return {\n id: 'id',\n number: numberColumn,\n placedAt: 'placed_at',\n lineItemCount: 'line_item_count',\n grandTotalNetAmount: 'grand_total_net_amount',\n grandTotalGrossAmount: 'grand_total_gross_amount',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n }\n}\n\nconst mapUpdateResponse = (entity: any) => ({\n id: entity?.id ?? null,\n orderNumber: entity?.orderNumber ?? null,\n quoteNumber: entity?.quoteNumber ?? null,\n customerEntityId: entity?.customerEntityId ?? null,\n customerContactId: entity?.customerContactId ?? null,\n customerSnapshot: entity?.customerSnapshot ?? null,\n metadata: entity?.metadata ?? null,\n externalReference: entity?.externalReference ?? null,\n customerReference: entity?.customerReference ?? null,\n comment: entity?.comments ?? null,\n statusEntryId: (entity as any)?.statusEntryId ?? null,\n status: (entity as any)?.status ?? null,\n channelId: (entity as any)?.channelId ?? null,\n customerName: resolveCustomerName(entity?.customerSnapshot ?? null, entity?.customerEntityId ?? null),\n contactEmail:\n resolveCustomerEmail(entity?.customerSnapshot ?? null) ??\n (typeof entity?.metadata?.customerEmail === 'string' ? entity.metadata.customerEmail : null),\n currencyCode: entity?.currencyCode ?? null,\n placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,\n expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,\n shippingAddressId: entity?.shippingAddressId ?? null,\n billingAddressId: entity?.billingAddressId ?? null,\n shippingAddressSnapshot: entity?.shippingAddressSnapshot ?? null,\n billingAddressSnapshot: entity?.billingAddressSnapshot ?? null,\n shippingMethodId: entity?.shippingMethodId ?? null,\n shippingMethodCode: entity?.shippingMethodCode ?? null,\n shippingMethodSnapshot: entity?.shippingMethodSnapshot ?? null,\n paymentMethodId: entity?.paymentMethodId ?? null,\n paymentMethodCode: entity?.paymentMethodCode ?? null,\n paymentMethodSnapshot: entity?.paymentMethodSnapshot ?? null,\n})\n\nconst attachTags = async (payload: any, ctx: any) => {\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, any>>) : []\n if (!items.length) return\n const ids = items\n .map((item) => (item && typeof item.id === 'string' ? item.id : null))\n .filter((id): id is string => !!id)\n if (!ids.length) return\n const em = ctx?.container?.resolve ? (ctx.container.resolve('em') as any) : null\n if (!em) return\n const where: Record<string, unknown> = {\n documentId: { $in: ids },\n documentKind: ctx?.bindingKind ?? null,\n }\n if (ctx?.auth?.tenantId) where.tenantId = ctx.auth.tenantId\n const orgIds =\n Array.isArray(ctx?.organizationIds) && ctx.organizationIds.length\n ? ctx.organizationIds.filter((val: string | null) => !!val)\n : ctx?.selectedOrganizationId\n ? [ctx.selectedOrganizationId]\n : []\n if (orgIds.length) where.organizationId = { $in: orgIds }\n const assignments = await em.find(\n SalesDocumentTagAssignment,\n where,\n { populate: ['tag'] },\n )\n const grouped = new Map<string, Array<{ id: string; label: string; color: string | null }>>()\n assignments.forEach((assignment: any) => {\n const tag = assignment?.tag\n const documentId = assignment?.documentId\n if (!tag || typeof tag.id !== 'string' || typeof documentId !== 'string') return\n const entry = {\n id: tag.id,\n label: typeof tag.label === 'string' && tag.label.trim().length ? tag.label : tag.slug ?? tag.id,\n color: typeof tag.color === 'string' && tag.color.trim().length ? tag.color : null,\n }\n const list = grouped.get(documentId) ?? []\n list.push(entry)\n grouped.set(documentId, list)\n })\n items.forEach((item: Record<string, any>) => {\n const id = item && typeof item.id === 'string' ? item.id : null\n if (!id) return\n const list = grouped.get(id)\n if (list) item.tags = list\n })\n}\n\nasync function ensureNumberEditPermission(\n ctx: CrudCtx,\n translate: (key: string, fallback?: string) => string\n) {\n const rbac = ctx.container?.resolve?.('rbacService') as RbacService | null\n const auth = ctx.auth\n if (!rbac || !auth?.sub) return\n const ok = await rbac.userHasAllFeatures(auth.sub, ['sales.documents.number.edit'], {\n tenantId: auth.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? auth.orgId ?? null,\n })\n if (!ok) {\n throw new CrudHttpError(403, {\n error: translate('sales.documents.errors.number_edit_forbidden', 'You cannot edit document numbers.'),\n })\n }\n}\n\nexport function buildDocumentCrudOptions(binding: DocumentBinding) {\n const numberColumn = binding.numberField === 'orderNumber' ? 'order_number' : 'quote_number'\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n\n const routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [binding.viewFeature] },\n POST: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n PUT: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n DELETE: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n }\n\n const commonFields = [\n 'id',\n numberColumn,\n 'status',\n 'status_entry_id',\n 'customer_entity_id',\n 'customer_contact_id',\n 'billing_address_id',\n 'shipping_address_id',\n 'customer_snapshot',\n 'billing_address_snapshot',\n 'shipping_address_snapshot',\n 'shipping_method_id',\n 'shipping_method_code',\n 'shipping_method_snapshot',\n 'payment_method_id',\n 'payment_method_code',\n 'payment_method_snapshot',\n 'customer_reference',\n 'metadata',\n 'external_reference',\n 'currency_code',\n 'comments',\n 'channel_id',\n 'placed_at',\n 'line_item_count',\n 'subtotal_net_amount',\n 'subtotal_gross_amount',\n 'tax_total_amount',\n 'discount_total_amount',\n 'grand_total_net_amount',\n 'grand_total_gross_amount',\n 'totals_snapshot',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n ]\n\n const orderOnlyFields = [\n 'expected_delivery_at',\n 'shipping_net_amount',\n 'shipping_gross_amount',\n 'surcharge_total_amount',\n 'paid_total_amount',\n 'refunded_total_amount',\n 'outstanding_amount',\n ]\n\n const quoteOnlyFields = ['valid_from', 'valid_until']\n\n const listFields = [\n ...commonFields,\n ...(binding.kind === 'order' ? orderOnlyFields : quoteOnlyFields),\n ]\n\n return {\n metadata: routeMetadata,\n orm: {\n entity: binding.entity as any,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: {\n entityType: binding.entityId,\n },\n list: {\n schema: listSchema,\n entityId: binding.entityId,\n fields: listFields,\n sortFieldMap: buildSortMap(numberColumn),\n buildFilters: async (query: any) => buildFilters(query, numberColumn, binding.kind),\n decorateCustomFields: { entityIds: [binding.entityId] },\n joins: [\n {\n alias: 'tag_assignments',\n table: 'sales_document_tag_assignments',\n from: { field: 'id' },\n to: { field: 'document_id' },\n type: 'left' as const,\n },\n ],\n transformItem: (item: any) => {\n const toNumber = (value: unknown): number | null => {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n const base = {\n id: item.id,\n [binding.numberField]: item[numberColumn] ?? null,\n status: item.status ?? null,\n statusEntryId: item.status_entry_id ?? null,\n customerEntityId: item.customer_entity_id ?? null,\n customerContactId: item.customer_contact_id ?? null,\n billingAddressId: item.billing_address_id ?? null,\n shippingAddressId: item.shipping_address_id ?? null,\n shippingMethodId: item.shipping_method_id ?? null,\n shippingMethodCode: item.shipping_method_code ?? null,\n shippingMethodSnapshot: item.shipping_method_snapshot ?? null,\n paymentMethodId: item.payment_method_id ?? null,\n paymentMethodCode: item.payment_method_code ?? null,\n paymentMethodSnapshot: item.payment_method_snapshot ?? null,\n currencyCode: item.currency_code ?? null,\n channelId: item.channel_id ?? null,\n externalReference: item.external_reference ?? null,\n customerReference: item.customer_reference ?? null,\n placedAt: item.placed_at ?? null,\n expectedDeliveryAt: item.expected_delivery_at ?? null,\n comment: item.comments ?? null,\n validFrom: item.valid_from ?? null,\n validUntil: item.valid_until ?? null,\n lineItemCount: toNumber(item.line_item_count),\n subtotalNetAmount: toNumber(item.subtotal_net_amount),\n subtotalGrossAmount: toNumber(item.subtotal_gross_amount),\n discountTotalAmount: toNumber(item.discount_total_amount),\n taxTotalAmount: toNumber(item.tax_total_amount),\n shippingNetAmount: toNumber(item.shipping_net_amount),\n shippingGrossAmount: toNumber(item.shipping_gross_amount),\n surchargeTotalAmount: toNumber(item.surcharge_total_amount),\n grandTotalNetAmount: toNumber(item.grand_total_net_amount),\n grandTotalGrossAmount: toNumber(item.grand_total_gross_amount),\n paidTotalAmount: toNumber(item.paid_total_amount),\n refundedTotalAmount: toNumber(item.refunded_total_amount),\n outstandingAmount: toNumber(item.outstanding_amount),\n customerSnapshot: item.customer_snapshot ?? null,\n billingAddressSnapshot: item.billing_address_snapshot ?? null,\n shippingAddressSnapshot: item.shipping_address_snapshot ?? null,\n metadata: item.metadata ?? null,\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n const cfEntries = extractAllCustomFieldEntries(item as Record<string, unknown>)\n const normalized = { ...base }\n Object.keys(normalized).forEach((key) => {\n if (key.startsWith('cf:')) delete (normalized as any)[key]\n })\n return Object.keys(cfEntries).length ? { ...normalized, ...cfEntries } : normalized\n },\n },\n actions: {\n create: {\n commandId: binding.createCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const parsed = parseScopedCommandInput(\n createSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) => ({ id: result?.orderId ?? result?.quoteId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: binding.updateCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const numberValue =\n binding.kind === 'order'\n ? (base as Record<string, unknown>).orderNumber\n : (base as Record<string, unknown>).quoteNumber\n if (typeof numberValue === 'string') {\n await ensureNumberEditPermission(ctx, translate)\n }\n const parsed = parseScopedCommandInput(\n documentUpdateSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) =>\n mapUpdateResponse((result as any)?.order ?? (result as any)?.quote ?? result),\n },\n delete: {\n commandId: binding.deleteCommandId,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }: { parsed: any; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload: any, ctx: CrudCtx) => {\n await attachTags(payload, { ...ctx, bindingKind: binding.kind })\n if (binding.kind === 'order' && Array.isArray(payload?.items) && payload.items.length === 1) {\n const item = payload.items[0] as Record<string, unknown>\n const orderId = typeof item?.id === 'string' ? item.id : null\n const tenantId = typeof item?.tenantId === 'string' ? item.tenantId : ctx?.auth?.tenantId ?? null\n const organizationId =\n typeof item?.organizationId === 'string' ? item.organizationId : ctx?.selectedOrganizationId ?? ctx?.auth?.orgId ?? null\n if (orderId && tenantId && organizationId) {\n const em = ctx?.container?.resolve?.('em') as import('@mikro-orm/postgresql').EntityManager | undefined\n if (em) {\n const totals = await recalculateOrderTotalsForDisplay(\n em,\n ctx.container,\n orderId,\n { tenantId, organizationId },\n )\n if (totals) {\n Object.assign(item, {\n subtotalNetAmount: totals.subtotalNetAmount,\n subtotalGrossAmount: totals.subtotalGrossAmount,\n discountTotalAmount: totals.discountTotalAmount,\n taxTotalAmount: totals.taxTotalAmount,\n shippingNetAmount: totals.shippingNetAmount,\n shippingGrossAmount: totals.shippingGrossAmount,\n surchargeTotalAmount: totals.surchargeTotalAmount,\n grandTotalNetAmount: totals.grandTotalNetAmount,\n grandTotalGrossAmount: totals.grandTotalGrossAmount,\n paidTotalAmount: totals.paidTotalAmount,\n refundedTotalAmount: totals.refundedTotalAmount,\n outstandingAmount: totals.outstandingAmount,\n })\n }\n }\n }\n }\n },\n },\n }\n}\n\nexport function buildDocumentOpenApi(binding: DocumentBinding) {\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n const itemSchema = z.object({\n id: z.string().uuid(),\n [binding.numberField]: z.string().nullable(),\n status: z.string().nullable(),\n statusEntryId: z.string().uuid().nullable().optional(),\n customerEntityId: z.string().uuid().nullable(),\n customerContactId: z.string().uuid().nullable(),\n billingAddressId: z.string().uuid().nullable(),\n shippingAddressId: z.string().uuid().nullable(),\n customerReference: z.string().nullable().optional(),\n externalReference: z.string().nullable().optional(),\n comment: z.string().nullable().optional(),\n placedAt: z.string().nullable().optional(),\n expectedDeliveryAt: z.string().nullable().optional(),\n customerSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n billingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingMethodId: z.string().uuid().nullable().optional(),\n shippingMethodCode: z.string().nullable().optional(),\n shippingMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n paymentMethodId: z.string().uuid().nullable().optional(),\n paymentMethodCode: z.string().nullable().optional(),\n paymentMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n currencyCode: z.string().nullable(),\n channelId: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n validFrom: z.string().nullable().optional(),\n validUntil: z.string().nullable().optional(),\n lineItemCount: z.number().nullable().optional(),\n subtotalNetAmount: z.number().nullable().optional(),\n subtotalGrossAmount: z.number().nullable().optional(),\n discountTotalAmount: z.number().nullable().optional(),\n taxTotalAmount: z.number().nullable().optional(),\n shippingNetAmount: z.number().nullable().optional(),\n shippingGrossAmount: z.number().nullable().optional(),\n surchargeTotalAmount: z.number().nullable().optional(),\n grandTotalNetAmount: z.number().nullable().optional(),\n grandTotalGrossAmount: z.number().nullable().optional(),\n paidTotalAmount: z.number().nullable().optional(),\n refundedTotalAmount: z.number().nullable().optional(),\n outstandingAmount: z.number().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n customFields: z.record(z.string(), z.unknown()).optional(),\n customValues: z.record(z.string(), z.unknown()).optional(),\n })\n\n const listResponseSchema = createPagedListResponseSchema(itemSchema)\n\n return createSalesCrudOpenApi({\n resourceName: binding.kind === 'order' ? 'Order' : 'Quote',\n querySchema: listSchema,\n listResponseSchema,\n create: {\n schema: createSchema,\n responseSchema: z.object({ id: z.string().uuid().nullable() }),\n description: `Creates a new sales ${binding.kind}.`,\n },\n del: {\n schema: defaultDeleteRequestSchema,\n responseSchema: z.object({ ok: z.boolean() }),\n description: `Deletes a sales ${binding.kind}.`,\n },\n })\n}\n\n// Compatibility wrapper\nexport function createDocumentCrudRoute(binding: DocumentBinding) {\n const crud = makeCrudRoute(buildDocumentCrudOptions(binding))\n const { GET, POST, PUT, DELETE } = crud\n return { GET, POST, PUT, DELETE, openApi: buildDocumentOpenApi(binding), metadata: crud.metadata }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { z } from 'zod'\nimport { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'\nimport { splitCustomFieldPayload, extractAllCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { E } from '#generated/entities.ids.generated'\nimport type { SalesOrder, SalesQuote } from '../../data/entities'\nimport { SalesDocumentTagAssignment } from '../../data/entities'\nimport {\n orderCreateSchema,\n quoteCreateSchema,\n} from '../../data/validators'\nimport {\n createPagedListResponseSchema,\n createSalesCrudOpenApi,\n defaultDeleteRequestSchema,\n} from '../openapi'\nimport { parseScopedCommandInput, resolveCrudRecordId } from '../utils'\nimport { documentUpdateSchema } from '../../commands/documents'\nimport { escapeLikePattern } from '@open-mercato/shared/lib/db/escapeLikePattern'\nimport { parseBooleanToken } from '@open-mercato/shared/lib/boolean'\nimport type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'\nimport { recalculateOrderTotalsForDisplay } from '../../commands/returns'\nimport { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'\n\ntype DocumentKind = 'order' | 'quote'\n\ntype DocumentBinding = {\n kind: DocumentKind\n entity: typeof SalesOrder | typeof SalesQuote\n entityId: (typeof E.sales)[keyof typeof E.sales]\n numberField: 'orderNumber' | 'quoteNumber'\n createCommandId: string\n updateCommandId: string\n deleteCommandId: string\n manageFeature: string\n viewFeature: string\n}\n\nconst rawBodySchema = z.object({}).passthrough()\n\nconst normalizeJsonRecord = (value: unknown): Record<string, unknown> | null => {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n return value as Record<string, unknown>\n }\n if (typeof value !== 'string') return null\n const parsed = parseDecryptedFieldValue(value)\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed)\n ? parsed as Record<string, unknown>\n : null\n}\n\nconst resolveCustomerName = (snapshot: Record<string, unknown> | null, fallback?: string | null) => {\n if (!snapshot) return fallback ?? null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const contact = snapshot.contact as Record<string, unknown> | undefined\n const displayName = typeof customer?.displayName === 'string' ? customer.displayName : null\n if (displayName) return displayName\n const first = typeof contact?.firstName === 'string' ? contact.firstName : null\n const last = typeof contact?.lastName === 'string' ? contact.lastName : null\n const preferred = typeof contact?.preferredName === 'string' ? contact.preferredName : null\n const parts = [preferred ?? first, last].filter((part) => part && part.trim().length)\n if (parts.length) return parts.join(' ')\n return fallback ?? null\n}\n\nconst resolveCustomerEmail = (snapshot: Record<string, unknown> | null) => {\n if (!snapshot) return null\n const customer = snapshot.customer as Record<string, unknown> | undefined\n const primary = typeof customer?.primaryEmail === 'string' ? customer.primaryEmail : null\n return primary ?? null\n}\n\nconst listSchema = z\n .object({\n page: z.coerce.number().min(1).default(1),\n pageSize: z.coerce.number().min(1).max(100).default(50),\n search: z.string().optional(),\n id: z.string().uuid().optional(),\n customerId: z.string().uuid().optional(),\n channelId: z.string().uuid().optional(),\n lineItemCountMin: z.coerce.number().min(0).optional(),\n lineItemCountMax: z.coerce.number().min(0).optional(),\n totalNetMin: z.coerce.number().optional(),\n totalNetMax: z.coerce.number().optional(),\n totalGrossMin: z.coerce.number().optional(),\n totalGrossMax: z.coerce.number().optional(),\n dateFrom: z.string().optional(),\n dateTo: z.string().optional(),\n tagIds: z.string().optional(),\n tagIdsEmpty: z.string().optional(),\n sortField: z.string().optional(),\n sortDir: z.enum(['asc', 'desc']).optional(),\n withDeleted: z.coerce.boolean().optional(),\n })\n .passthrough()\n\ntype ListQuery = z.infer<typeof listSchema>\n\nfunction buildFilters(query: ListQuery, numberColumn: string, kind: DocumentKind) {\n const filters: Record<string, unknown> = {}\n if (query.id) filters.id = { $eq: query.id }\n if (query.search && query.search.trim().length > 0) {\n const term = `%${escapeLikePattern(query.search.trim())}%`\n filters[numberColumn] = { $ilike: term }\n }\n if (query.customerId) {\n filters.customer_entity_id = { $eq: query.customerId }\n }\n if (query.channelId) {\n filters.channel_id = { $eq: query.channelId }\n }\n const lineRange: Record<string, number> = {}\n if (typeof query.lineItemCountMin === 'number') lineRange.$gte = query.lineItemCountMin\n if (typeof query.lineItemCountMax === 'number') lineRange.$lte = query.lineItemCountMax\n if (Object.keys(lineRange).length) {\n filters.line_item_count = lineRange\n }\n const netRange: Record<string, number> = {}\n if (typeof query.totalNetMin === 'number') netRange.$gte = query.totalNetMin\n if (typeof query.totalNetMax === 'number') netRange.$lte = query.totalNetMax\n if (Object.keys(netRange).length) {\n filters.grand_total_net_amount = netRange\n }\n const grossRange: Record<string, number> = {}\n if (typeof query.totalGrossMin === 'number') grossRange.$gte = query.totalGrossMin\n if (typeof query.totalGrossMax === 'number') grossRange.$lte = query.totalGrossMax\n if (Object.keys(grossRange).length) {\n filters.grand_total_gross_amount = grossRange\n }\n const dateRange: Record<string, Date> = {}\n if (query.dateFrom) {\n const from = new Date(query.dateFrom)\n if (!Number.isNaN(from.getTime())) dateRange.$gte = from\n }\n if (query.dateTo) {\n const to = new Date(query.dateTo)\n if (!Number.isNaN(to.getTime())) dateRange.$lte = to\n }\n if (Object.keys(dateRange).length) {\n filters.created_at = dateRange\n }\n const tagIdsRaw = typeof query.tagIds === 'string' ? query.tagIds : ''\n const tagIds = tagIdsRaw\n .split(',')\n .map((value) => value.trim())\n .filter((value) => value.length > 0)\n if (parseBooleanToken(query.tagIdsEmpty) === true) {\n filters.id = { $eq: '00000000-0000-0000-0000-000000000000' }\n } else if (tagIds.length) {\n filters['tag_assignments.tag_id'] = { $in: tagIds }\n filters['tag_assignments.document_kind'] = { $eq: kind }\n }\n return filters\n}\n\nfunction buildSortMap(numberColumn: string) {\n return {\n id: 'id',\n number: numberColumn,\n placedAt: 'placed_at',\n lineItemCount: 'line_item_count',\n grandTotalNetAmount: 'grand_total_net_amount',\n grandTotalGrossAmount: 'grand_total_gross_amount',\n createdAt: 'created_at',\n updatedAt: 'updated_at',\n }\n}\n\nconst mapUpdateResponse = (entity: any) => {\n const customerSnapshot = normalizeJsonRecord(entity?.customerSnapshot)\n const metadata = normalizeJsonRecord(entity?.metadata)\n\n return {\n id: entity?.id ?? null,\n orderNumber: entity?.orderNumber ?? null,\n quoteNumber: entity?.quoteNumber ?? null,\n customerEntityId: entity?.customerEntityId ?? null,\n customerContactId: entity?.customerContactId ?? null,\n customerSnapshot,\n metadata,\n externalReference: entity?.externalReference ?? null,\n customerReference: entity?.customerReference ?? null,\n comment: entity?.comments ?? null,\n statusEntryId: (entity as any)?.statusEntryId ?? null,\n status: (entity as any)?.status ?? null,\n channelId: (entity as any)?.channelId ?? null,\n customerName: resolveCustomerName(customerSnapshot, entity?.customerEntityId ?? null),\n contactEmail:\n resolveCustomerEmail(customerSnapshot) ??\n (typeof metadata?.customerEmail === 'string' ? metadata.customerEmail : null),\n currencyCode: entity?.currencyCode ?? null,\n placedAt: entity?.placedAt ? entity.placedAt.toISOString() : null,\n expectedDeliveryAt: entity?.expectedDeliveryAt ? entity.expectedDeliveryAt.toISOString() : null,\n shippingAddressId: entity?.shippingAddressId ?? null,\n billingAddressId: entity?.billingAddressId ?? null,\n shippingAddressSnapshot: normalizeJsonRecord(entity?.shippingAddressSnapshot),\n billingAddressSnapshot: normalizeJsonRecord(entity?.billingAddressSnapshot),\n shippingMethodId: entity?.shippingMethodId ?? null,\n shippingMethodCode: entity?.shippingMethodCode ?? null,\n shippingMethodSnapshot: normalizeJsonRecord(entity?.shippingMethodSnapshot),\n paymentMethodId: entity?.paymentMethodId ?? null,\n paymentMethodCode: entity?.paymentMethodCode ?? null,\n paymentMethodSnapshot: normalizeJsonRecord(entity?.paymentMethodSnapshot),\n }\n}\n\nconst attachTags = async (payload: any, ctx: any) => {\n const items = Array.isArray(payload?.items) ? (payload.items as Array<Record<string, any>>) : []\n if (!items.length) return\n const ids = items\n .map((item) => (item && typeof item.id === 'string' ? item.id : null))\n .filter((id): id is string => !!id)\n if (!ids.length) return\n const em = ctx?.container?.resolve ? (ctx.container.resolve('em') as any) : null\n if (!em) return\n const where: Record<string, unknown> = {\n documentId: { $in: ids },\n documentKind: ctx?.bindingKind ?? null,\n }\n if (ctx?.auth?.tenantId) where.tenantId = ctx.auth.tenantId\n const orgIds =\n Array.isArray(ctx?.organizationIds) && ctx.organizationIds.length\n ? ctx.organizationIds.filter((val: string | null) => !!val)\n : ctx?.selectedOrganizationId\n ? [ctx.selectedOrganizationId]\n : []\n if (orgIds.length) where.organizationId = { $in: orgIds }\n const assignments = await em.find(\n SalesDocumentTagAssignment,\n where,\n { populate: ['tag'] },\n )\n const grouped = new Map<string, Array<{ id: string; label: string; color: string | null }>>()\n assignments.forEach((assignment: any) => {\n const tag = assignment?.tag\n const documentId = assignment?.documentId\n if (!tag || typeof tag.id !== 'string' || typeof documentId !== 'string') return\n const entry = {\n id: tag.id,\n label: typeof tag.label === 'string' && tag.label.trim().length ? tag.label : tag.slug ?? tag.id,\n color: typeof tag.color === 'string' && tag.color.trim().length ? tag.color : null,\n }\n const list = grouped.get(documentId) ?? []\n list.push(entry)\n grouped.set(documentId, list)\n })\n items.forEach((item: Record<string, any>) => {\n const id = item && typeof item.id === 'string' ? item.id : null\n if (!id) return\n const list = grouped.get(id)\n if (list) item.tags = list\n })\n}\n\nasync function ensureNumberEditPermission(\n ctx: CrudCtx,\n translate: (key: string, fallback?: string) => string\n) {\n const rbac = ctx.container?.resolve?.('rbacService') as RbacService | null\n const auth = ctx.auth\n if (!rbac || !auth?.sub) return\n const ok = await rbac.userHasAllFeatures(auth.sub, ['sales.documents.number.edit'], {\n tenantId: auth.tenantId ?? null,\n organizationId: ctx.selectedOrganizationId ?? auth.orgId ?? null,\n })\n if (!ok) {\n throw new CrudHttpError(403, {\n error: translate('sales.documents.errors.number_edit_forbidden', 'You cannot edit document numbers.'),\n })\n }\n}\n\nexport function buildDocumentCrudOptions(binding: DocumentBinding) {\n const numberColumn = binding.numberField === 'orderNumber' ? 'order_number' : 'quote_number'\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n\n const routeMetadata = {\n GET: { requireAuth: true, requireFeatures: [binding.viewFeature] },\n POST: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n PUT: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n DELETE: { requireAuth: true, requireFeatures: [binding.manageFeature] },\n }\n\n const commonFields = [\n 'id',\n numberColumn,\n 'status',\n 'status_entry_id',\n 'customer_entity_id',\n 'customer_contact_id',\n 'billing_address_id',\n 'shipping_address_id',\n 'customer_snapshot',\n 'billing_address_snapshot',\n 'shipping_address_snapshot',\n 'shipping_method_id',\n 'shipping_method_code',\n 'shipping_method_snapshot',\n 'payment_method_id',\n 'payment_method_code',\n 'payment_method_snapshot',\n 'customer_reference',\n 'metadata',\n 'external_reference',\n 'currency_code',\n 'comments',\n 'channel_id',\n 'placed_at',\n 'line_item_count',\n 'subtotal_net_amount',\n 'subtotal_gross_amount',\n 'tax_total_amount',\n 'discount_total_amount',\n 'grand_total_net_amount',\n 'grand_total_gross_amount',\n 'totals_snapshot',\n 'organization_id',\n 'tenant_id',\n 'created_at',\n 'updated_at',\n ]\n\n const orderOnlyFields = [\n 'expected_delivery_at',\n 'shipping_net_amount',\n 'shipping_gross_amount',\n 'surcharge_total_amount',\n 'paid_total_amount',\n 'refunded_total_amount',\n 'outstanding_amount',\n ]\n\n const quoteOnlyFields = ['valid_from', 'valid_until']\n\n const listFields = [\n ...commonFields,\n ...(binding.kind === 'order' ? orderOnlyFields : quoteOnlyFields),\n ]\n\n return {\n metadata: routeMetadata,\n orm: {\n entity: binding.entity as any,\n idField: 'id',\n orgField: 'organizationId',\n tenantField: 'tenantId',\n softDeleteField: 'deletedAt',\n },\n indexer: {\n entityType: binding.entityId,\n },\n list: {\n schema: listSchema,\n entityId: binding.entityId,\n fields: listFields,\n sortFieldMap: buildSortMap(numberColumn),\n buildFilters: async (query: any) => buildFilters(query, numberColumn, binding.kind),\n decorateCustomFields: { entityIds: [binding.entityId] },\n joins: [\n {\n alias: 'tag_assignments',\n table: 'sales_document_tag_assignments',\n from: { field: 'id' },\n to: { field: 'document_id' },\n type: 'left' as const,\n },\n ],\n transformItem: (item: any) => {\n const toNumber = (value: unknown): number | null => {\n if (typeof value === 'number') return Number.isNaN(value) ? null : value\n if (typeof value === 'string' && value.trim().length) {\n const parsed = Number(value)\n return Number.isNaN(parsed) ? null : parsed\n }\n return null\n }\n const base = {\n id: item.id,\n [binding.numberField]: item[numberColumn] ?? null,\n status: item.status ?? null,\n statusEntryId: item.status_entry_id ?? null,\n customerEntityId: item.customer_entity_id ?? null,\n customerContactId: item.customer_contact_id ?? null,\n billingAddressId: item.billing_address_id ?? null,\n shippingAddressId: item.shipping_address_id ?? null,\n shippingMethodId: item.shipping_method_id ?? null,\n shippingMethodCode: item.shipping_method_code ?? null,\n shippingMethodSnapshot: normalizeJsonRecord(item.shipping_method_snapshot),\n paymentMethodId: item.payment_method_id ?? null,\n paymentMethodCode: item.payment_method_code ?? null,\n paymentMethodSnapshot: normalizeJsonRecord(item.payment_method_snapshot),\n currencyCode: item.currency_code ?? null,\n channelId: item.channel_id ?? null,\n externalReference: item.external_reference ?? null,\n customerReference: item.customer_reference ?? null,\n placedAt: item.placed_at ?? null,\n expectedDeliveryAt: item.expected_delivery_at ?? null,\n comment: item.comments ?? null,\n validFrom: item.valid_from ?? null,\n validUntil: item.valid_until ?? null,\n lineItemCount: toNumber(item.line_item_count),\n subtotalNetAmount: toNumber(item.subtotal_net_amount),\n subtotalGrossAmount: toNumber(item.subtotal_gross_amount),\n discountTotalAmount: toNumber(item.discount_total_amount),\n taxTotalAmount: toNumber(item.tax_total_amount),\n shippingNetAmount: toNumber(item.shipping_net_amount),\n shippingGrossAmount: toNumber(item.shipping_gross_amount),\n surchargeTotalAmount: toNumber(item.surcharge_total_amount),\n grandTotalNetAmount: toNumber(item.grand_total_net_amount),\n grandTotalGrossAmount: toNumber(item.grand_total_gross_amount),\n paidTotalAmount: toNumber(item.paid_total_amount),\n refundedTotalAmount: toNumber(item.refunded_total_amount),\n outstandingAmount: toNumber(item.outstanding_amount),\n customerSnapshot: normalizeJsonRecord(item.customer_snapshot),\n billingAddressSnapshot: normalizeJsonRecord(item.billing_address_snapshot),\n shippingAddressSnapshot: normalizeJsonRecord(item.shipping_address_snapshot),\n metadata: normalizeJsonRecord(item.metadata),\n organizationId: item.organization_id ?? null,\n tenantId: item.tenant_id ?? null,\n createdAt: item.created_at,\n updatedAt: item.updated_at,\n }\n const cfEntries = extractAllCustomFieldEntries(item as Record<string, unknown>)\n const normalized = { ...base }\n Object.keys(normalized).forEach((key) => {\n if (key.startsWith('cf:')) delete (normalized as any)[key]\n })\n return Object.keys(cfEntries).length ? { ...normalized, ...cfEntries } : normalized\n },\n },\n actions: {\n create: {\n commandId: binding.createCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const parsed = parseScopedCommandInput(\n createSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) => ({ id: result?.orderId ?? result?.quoteId ?? result?.id ?? null }),\n status: 201,\n },\n update: {\n commandId: binding.updateCommandId,\n schema: rawBodySchema,\n mapInput: async ({ raw, ctx }: { raw: unknown; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const { base, custom } = splitCustomFieldPayload(raw ?? {})\n const numberValue =\n binding.kind === 'order'\n ? (base as Record<string, unknown>).orderNumber\n : (base as Record<string, unknown>).quoteNumber\n if (typeof numberValue === 'string') {\n await ensureNumberEditPermission(ctx, translate)\n }\n const parsed = parseScopedCommandInput(\n documentUpdateSchema,\n Object.keys(custom).length ? { ...base, customFields: custom } : base,\n ctx,\n translate,\n )\n return parsed\n },\n response: ({ result }: { result: any }) =>\n mapUpdateResponse((result as any)?.order ?? (result as any)?.quote ?? result),\n },\n delete: {\n commandId: binding.deleteCommandId,\n schema: rawBodySchema,\n mapInput: async ({ parsed, ctx }: { parsed: any; ctx: CrudCtx }) => {\n const { translate } = await resolveTranslations()\n const id = resolveCrudRecordId(parsed, ctx, translate)\n return { id }\n },\n response: () => ({ ok: true }),\n },\n },\n hooks: {\n afterList: async (payload: any, ctx: CrudCtx) => {\n await attachTags(payload, { ...ctx, bindingKind: binding.kind })\n if (binding.kind === 'order' && Array.isArray(payload?.items) && payload.items.length === 1) {\n const item = payload.items[0] as Record<string, unknown>\n const orderId = typeof item?.id === 'string' ? item.id : null\n const tenantId = typeof item?.tenantId === 'string' ? item.tenantId : ctx?.auth?.tenantId ?? null\n const organizationId =\n typeof item?.organizationId === 'string' ? item.organizationId : ctx?.selectedOrganizationId ?? ctx?.auth?.orgId ?? null\n if (orderId && tenantId && organizationId) {\n const em = ctx?.container?.resolve?.('em') as import('@mikro-orm/postgresql').EntityManager | undefined\n if (em) {\n const totals = await recalculateOrderTotalsForDisplay(\n em,\n ctx.container,\n orderId,\n { tenantId, organizationId },\n )\n if (totals) {\n Object.assign(item, {\n subtotalNetAmount: totals.subtotalNetAmount,\n subtotalGrossAmount: totals.subtotalGrossAmount,\n discountTotalAmount: totals.discountTotalAmount,\n taxTotalAmount: totals.taxTotalAmount,\n shippingNetAmount: totals.shippingNetAmount,\n shippingGrossAmount: totals.shippingGrossAmount,\n surchargeTotalAmount: totals.surchargeTotalAmount,\n grandTotalNetAmount: totals.grandTotalNetAmount,\n grandTotalGrossAmount: totals.grandTotalGrossAmount,\n paidTotalAmount: totals.paidTotalAmount,\n refundedTotalAmount: totals.refundedTotalAmount,\n outstandingAmount: totals.outstandingAmount,\n })\n }\n }\n }\n }\n },\n },\n }\n}\n\nexport function buildDocumentOpenApi(binding: DocumentBinding) {\n const createSchema = binding.kind === 'order' ? orderCreateSchema : quoteCreateSchema\n const itemSchema = z.object({\n id: z.string().uuid(),\n [binding.numberField]: z.string().nullable(),\n status: z.string().nullable(),\n statusEntryId: z.string().uuid().nullable().optional(),\n customerEntityId: z.string().uuid().nullable(),\n customerContactId: z.string().uuid().nullable(),\n billingAddressId: z.string().uuid().nullable(),\n shippingAddressId: z.string().uuid().nullable(),\n customerReference: z.string().nullable().optional(),\n externalReference: z.string().nullable().optional(),\n comment: z.string().nullable().optional(),\n placedAt: z.string().nullable().optional(),\n expectedDeliveryAt: z.string().nullable().optional(),\n customerSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n billingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingAddressSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n shippingMethodId: z.string().uuid().nullable().optional(),\n shippingMethodCode: z.string().nullable().optional(),\n shippingMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n paymentMethodId: z.string().uuid().nullable().optional(),\n paymentMethodCode: z.string().nullable().optional(),\n paymentMethodSnapshot: z.record(z.string(), z.unknown()).nullable().optional(),\n currencyCode: z.string().nullable(),\n channelId: z.string().uuid().nullable(),\n organizationId: z.string().uuid().nullable(),\n tenantId: z.string().uuid().nullable(),\n validFrom: z.string().nullable().optional(),\n validUntil: z.string().nullable().optional(),\n lineItemCount: z.number().nullable().optional(),\n subtotalNetAmount: z.number().nullable().optional(),\n subtotalGrossAmount: z.number().nullable().optional(),\n discountTotalAmount: z.number().nullable().optional(),\n taxTotalAmount: z.number().nullable().optional(),\n shippingNetAmount: z.number().nullable().optional(),\n shippingGrossAmount: z.number().nullable().optional(),\n surchargeTotalAmount: z.number().nullable().optional(),\n grandTotalNetAmount: z.number().nullable().optional(),\n grandTotalGrossAmount: z.number().nullable().optional(),\n paidTotalAmount: z.number().nullable().optional(),\n refundedTotalAmount: z.number().nullable().optional(),\n outstandingAmount: z.number().nullable().optional(),\n createdAt: z.string(),\n updatedAt: z.string(),\n customFields: z.record(z.string(), z.unknown()).optional(),\n customValues: z.record(z.string(), z.unknown()).optional(),\n })\n\n const listResponseSchema = createPagedListResponseSchema(itemSchema)\n\n return createSalesCrudOpenApi({\n resourceName: binding.kind === 'order' ? 'Order' : 'Quote',\n querySchema: listSchema,\n listResponseSchema,\n create: {\n schema: createSchema,\n responseSchema: z.object({ id: z.string().uuid().nullable() }),\n description: `Creates a new sales ${binding.kind}.`,\n },\n del: {\n schema: defaultDeleteRequestSchema,\n responseSchema: z.object({ ok: z.boolean() }),\n description: `Deletes a sales ${binding.kind}.`,\n },\n })\n}\n\n// Compatibility wrapper\nexport function createDocumentCrudRoute(binding: DocumentBinding) {\n const crud = makeCrudRoute(buildDocumentCrudOptions(binding))\n const { GET, POST, PUT, DELETE } = crud\n return { GET, POST, PUT, DELETE, openApi: buildDocumentOpenApi(binding), metadata: crud.metadata }\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.6.1-develop.3069.d40b4417a9",
3
+ "version": "0.6.1-develop.3090.06ab462170",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -237,12 +237,12 @@
237
237
  "ts-pattern": "^5.0.0"
238
238
  },
239
239
  "peerDependencies": {
240
- "@open-mercato/ai-assistant": "0.6.1-develop.3069.d40b4417a9",
241
- "@open-mercato/shared": "0.6.1-develop.3069.d40b4417a9"
240
+ "@open-mercato/ai-assistant": "0.6.1-develop.3090.06ab462170",
241
+ "@open-mercato/shared": "0.6.1-develop.3090.06ab462170"
242
242
  },
243
243
  "devDependencies": {
244
- "@open-mercato/ai-assistant": "0.6.1-develop.3069.d40b4417a9",
245
- "@open-mercato/shared": "0.6.1-develop.3069.d40b4417a9",
244
+ "@open-mercato/ai-assistant": "0.6.1-develop.3090.06ab462170",
245
+ "@open-mercato/shared": "0.6.1-develop.3090.06ab462170",
246
246
  "@testing-library/dom": "^10.4.1",
247
247
  "@testing-library/jest-dom": "^6.9.1",
248
248
  "@testing-library/react": "^16.3.1",
@@ -8,6 +8,7 @@ import {
8
8
  type AccessLogListQuery,
9
9
  } from '@open-mercato/core/modules/audit_logs/data/validators'
10
10
  import { resolveTenantEncryptionService } from '@open-mercato/shared/lib/encryption/customFieldValues'
11
+ import { parseDecryptedFieldValue } from '@open-mercato/shared/lib/encryption/tenantDataEncryptionService'
11
12
  import { E } from '#generated/entities.ids.generated'
12
13
 
13
14
  const CORE_RESOURCE_KINDS = new Set<string>(['auth.user', 'auth.role'])
@@ -190,6 +191,25 @@ export class AccessLogService {
190
191
  },
191
192
  )
192
193
 
194
+ // Encrypted jsonb columns (`fields_json`, `context_json`) come back as raw
195
+ // JSON strings from the encryption subscriber after issue #1810 follow-up
196
+ // (entity-field decryption no longer auto-parses). Restore the structured
197
+ // shape on read so API consumers see typed objects/arrays.
198
+ for (const item of items) {
199
+ const rawFieldsJson = (item as { fieldsJson?: unknown }).fieldsJson
200
+ if (typeof rawFieldsJson === 'string') {
201
+ const parsed = parseDecryptedFieldValue(rawFieldsJson)
202
+ item.fieldsJson = Array.isArray(parsed) ? (parsed as string[]) : null
203
+ }
204
+ const rawContextJson = (item as { contextJson?: unknown }).contextJson
205
+ if (typeof rawContextJson === 'string') {
206
+ const parsed = parseDecryptedFieldValue(rawContextJson)
207
+ item.contextJson = parsed && typeof parsed === 'object' && !Array.isArray(parsed)
208
+ ? (parsed as Record<string, unknown>)
209
+ : null
210
+ }
211
+ }
212
+
193
213
  const totalPages = Math.max(1, Math.ceil((total || 0) / (pageSize || 1)))
194
214
  return { items, total, page, pageSize, totalPages }
195
215
  }
@@ -151,15 +151,23 @@ export class ActionLogService {
151
151
  ...decrypted,
152
152
  } as Record<string, unknown>
153
153
 
154
- merged.changesJson = deepDecrypt(merged.changesJson ?? merged.changes_json ?? entry.changesJson ?? entry.changes_json)
154
+ // Audit log jsonb columns are encrypted as JSON-stringified payloads. After the
155
+ // service-level `decryptEntityPayload` call (which now returns raw strings —
156
+ // see issue #1810 follow-up), reattach the structured shape via
157
+ // `parseDecryptedFieldValue` before running the recursive `deepDecrypt` walk
158
+ // so nested encrypted strings inside payload objects/arrays are handled.
159
+ const restoreJson = (value: unknown): unknown =>
160
+ typeof value === 'string' ? parseDecryptedFieldValue(value) : value
161
+
162
+ merged.changesJson = deepDecrypt(restoreJson(merged.changesJson ?? merged.changes_json ?? entry.changesJson ?? entry.changes_json))
155
163
  merged.changes_json = merged.changesJson
156
- merged.snapshotBefore = deepDecrypt(merged.snapshotBefore ?? merged.snapshot_before ?? entry.snapshotBefore ?? entry.snapshot_before)
164
+ merged.snapshotBefore = deepDecrypt(restoreJson(merged.snapshotBefore ?? merged.snapshot_before ?? entry.snapshotBefore ?? entry.snapshot_before))
157
165
  merged.snapshot_before = merged.snapshotBefore
158
- merged.snapshotAfter = deepDecrypt(merged.snapshotAfter ?? merged.snapshot_after ?? entry.snapshotAfter ?? entry.snapshot_after)
166
+ merged.snapshotAfter = deepDecrypt(restoreJson(merged.snapshotAfter ?? merged.snapshot_after ?? entry.snapshotAfter ?? entry.snapshot_after))
159
167
  merged.snapshot_after = merged.snapshotAfter
160
- merged.commandPayload = deepDecrypt(merged.commandPayload ?? merged.command_payload ?? entry.commandPayload ?? entry.command_payload)
168
+ merged.commandPayload = deepDecrypt(restoreJson(merged.commandPayload ?? merged.command_payload ?? entry.commandPayload ?? entry.command_payload))
161
169
  merged.command_payload = merged.commandPayload
162
- merged.contextJson = deepDecrypt(merged.contextJson ?? merged.context_json ?? entry.contextJson ?? entry.context_json)
170
+ merged.contextJson = deepDecrypt(restoreJson(merged.contextJson ?? merged.context_json ?? entry.contextJson ?? entry.context_json))
163
171
  merged.context_json = merged.contextJson
164
172
 
165
173
  return merged as T
@@ -9,7 +9,6 @@ import type { EntityManager } from '@mikro-orm/postgresql'
9
9
  import type { OpenApiRouteDoc } from '@open-mercato/shared/lib/openapi'
10
10
  import type { CommandBus } from '@open-mercato/shared/lib/commands'
11
11
  import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
12
- import { loadCustomFieldValues } from '@open-mercato/shared/lib/crud/custom-fields'
13
12
  import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
14
13
  import {
15
14
  runCrudMutationGuardAfterSuccess,
@@ -28,6 +27,7 @@ import {
28
27
  import { resolveCustomerInteractionFeatureFlags } from '../../lib/interactionFeatureFlags'
29
28
  import { resolveCustomersRequestContext } from '../../lib/interactionRequestContext'
30
29
  import { hydrateCanonicalInteractions } from '../../lib/interactionReadModel'
30
+ import { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'
31
31
 
32
32
  const listSchema = z.object({
33
33
  page: z.coerce.number().min(1).default(1),
@@ -253,81 +253,6 @@ function mapLegacyActivity(activity: CustomerActivity): ActivityItem {
253
253
  }
254
254
  }
255
255
 
256
- async function loadLegacyActivityCustomValues(
257
- em: EntityManager,
258
- activity: CustomerActivity,
259
- ): Promise<Record<string, unknown> | null> {
260
- const values = await loadCustomFieldValues({
261
- em,
262
- entityId: 'customers:customer_activity',
263
- recordIds: [activity.id],
264
- tenantIdByRecord: { [activity.id]: activity.tenantId },
265
- organizationIdByRecord: { [activity.id]: activity.organizationId },
266
- tenantFallbacks: [activity.tenantId],
267
- })
268
- return values[activity.id] ?? null
269
- }
270
-
271
- async function ensureCanonicalActivityBridge(
272
- em: EntityManager,
273
- commandBus: CommandBus,
274
- commandContext: Parameters<CommandBus['execute']>[1]['ctx'],
275
- activity: CustomerActivity,
276
- ): Promise<string> {
277
- const existing = await em.findOne(CustomerInteraction, { id: activity.id, tenantId: activity.tenantId })
278
- if (existing) return existing.id
279
-
280
- const entityId = typeof activity.entity === 'string' ? activity.entity : activity.entity.id
281
- const dealId = activity.deal
282
- ? (typeof activity.deal === 'string' ? activity.deal : activity.deal.id)
283
- : null
284
- const customValues = await loadLegacyActivityCustomValues(em, activity)
285
-
286
- await commandBus.execute('customers.interactions.create', {
287
- input: {
288
- id: activity.id,
289
- tenantId: activity.tenantId,
290
- organizationId: activity.organizationId,
291
- entityId,
292
- interactionType: activity.activityType,
293
- title: activity.subject ?? null,
294
- body: activity.body ?? null,
295
- occurredAt: activity.occurredAt ?? null,
296
- status: activity.occurredAt ? 'done' : 'planned',
297
- dealId,
298
- authorUserId: activity.authorUserId ?? null,
299
- appearanceIcon: activity.appearanceIcon ?? null,
300
- appearanceColor: activity.appearanceColor ?? null,
301
- source: CUSTOMER_INTERACTION_ACTIVITY_ADAPTER_SOURCE,
302
- ...(customValues ? { customValues } : {}),
303
- },
304
- ctx: commandContext,
305
- })
306
-
307
- return activity.id
308
- }
309
-
310
- async function resolveCanonicalActivityTargetId(
311
- em: EntityManager,
312
- commandBus: CommandBus,
313
- commandContext: Parameters<CommandBus['execute']>[1]['ctx'],
314
- targetId: string,
315
- tenantId: string,
316
- ): Promise<string> {
317
- const existing = await em.findOne(CustomerInteraction, { id: targetId, tenantId })
318
- if (existing) return existing.id
319
-
320
- const legacy = await em.findOne(CustomerActivity, { id: targetId, tenantId }, { populate: ['entity', 'deal'] })
321
- if (!legacy) return targetId
322
-
323
- return ensureCanonicalActivityBridge(
324
- em,
325
- commandBus,
326
- commandContext,
327
- legacy,
328
- )
329
- }
330
-
331
256
  async function listCanonicalActivities(
332
257
  em: EntityManager,
333
258
  container: { resolve: (name: string) => unknown },
@@ -21,6 +21,7 @@ const responseSchema = z.object({
21
21
  email: z.number(),
22
22
  meeting: z.number(),
23
23
  note: z.number(),
24
+ task: z.number(),
24
25
  total: z.number(),
25
26
  }),
26
27
  })
@@ -92,7 +93,7 @@ export async function GET(req: Request) {
92
93
  .groupBy('interaction_type')
93
94
  .execute() as Array<{ interaction_type: string; count: string | number }>
94
95
 
95
- const counts: Record<string, number> = { call: 0, email: 0, meeting: 0, note: 0 }
96
+ const counts: Record<string, number> = { call: 0, email: 0, meeting: 0, note: 0, task: 0 }
96
97
  let total = 0
97
98
  for (const row of rows) {
98
99
  const count = typeof row.count === 'string' ? parseInt(row.count, 10) : row.count
@@ -22,6 +22,8 @@ import {
22
22
  defaultOkResponseSchema,
23
23
  } from '../openapi'
24
24
  import { CUSTOMER_INTERACTION_ENTITY_ID } from '../../lib/interactionCompatibility'
25
+ import { resolveCanonicalActivityTargetId } from '../../lib/legacyActivityBridge'
26
+ import type { CommandBus, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'
25
27
 
26
28
  const rawBodySchema = z.object({}).passthrough()
27
29
 
@@ -93,7 +95,32 @@ const crud = makeCrudRoute({
93
95
  schema: rawBodySchema,
94
96
  mapInput: async ({ raw, ctx }) => {
95
97
  const { translate } = await resolveTranslations()
96
- return parseScopedCommandInput(interactionUpdateSchema, raw ?? {}, ctx, translate)
98
+ const parsed = parseScopedCommandInput(interactionUpdateSchema, raw ?? {}, ctx, translate)
99
+ // Bridge legacy `customer_activities` rows into `customer_interactions`
100
+ // before the canonical update runs so historical activities (#1807)
101
+ // remain editable through the new dialog. No-op when the canonical
102
+ // record already exists.
103
+ const tenantId = ctx.auth?.tenantId ?? null
104
+ if (typeof parsed.id === 'string' && tenantId) {
105
+ try {
106
+ const em = ctx.container.resolve('em') as EntityManager
107
+ const commandBus = ctx.container.resolve('commandBus') as CommandBus
108
+ const commandContext: CommandRuntimeContext = {
109
+ container: ctx.container,
110
+ auth: ctx.auth ?? null,
111
+ organizationScope: ctx.organizationScope ?? null,
112
+ selectedOrganizationId: ctx.selectedOrganizationId ?? null,
113
+ organizationIds: ctx.organizationIds ?? null,
114
+ request: ctx.request,
115
+ }
116
+ await resolveCanonicalActivityTargetId(em, commandBus, commandContext, parsed.id, tenantId)
117
+ } catch (err) {
118
+ // Bridging is best-effort; downstream lookup will surface a 404
119
+ // when neither canonical nor legacy rows exist.
120
+ console.warn('[customers.interactions.put] legacy bridge failed', { id: parsed.id, error: err })
121
+ }
122
+ }
123
+ return parsed
97
124
  },
98
125
  response: () => ({ ok: true }),
99
126
  },
@@ -185,19 +185,24 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
185
185
  logContext: 'customers.companies-v2',
186
186
  })
187
187
 
188
- const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; [key: string]: unknown }) => {
188
+ const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {
189
189
  const raw = activity as Record<string, unknown>
190
190
  const durationValue = typeof raw.duration === 'number'
191
191
  ? raw.duration
192
192
  : typeof raw.durationMinutes === 'number'
193
193
  ? raw.durationMinutes as number
194
194
  : null
195
- setScheduleEditData({
195
+ // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,
196
+ // taskPriority, …) round-trips on edit (#1808 phone persistence).
197
+ // Forward `occurredAt` so historical activity edits prefill from the original
198
+ // moment instead of "today" (#1807 prefill).
199
+ const editPayload = {
196
200
  id: activity.id,
197
201
  interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,
198
202
  title: typeof activity.title === 'string' ? activity.title : null,
199
203
  body: typeof activity.body === 'string' ? activity.body : null,
200
204
  scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,
205
+ occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,
201
206
  durationMinutes: durationValue,
202
207
  location: typeof raw.location === 'string' ? raw.location as string : null,
203
208
  allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,
@@ -210,7 +215,12 @@ export default function CompanyDetailV2Page({ params }: { params?: { id?: string
210
215
  guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'
211
216
  ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']
212
217
  : null,
213
- })
218
+ customValues: raw.customValues && typeof raw.customValues === 'object'
219
+ ? raw.customValues as Record<string, unknown>
220
+ : null,
221
+ phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,
222
+ } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }
223
+ setScheduleEditData(editPayload)
214
224
  setScheduleDialogOpen(true)
215
225
  }, [])
216
226
 
@@ -27,7 +27,7 @@ import { DealWonPopup } from '../../../../components/detail/DealWonPopup'
27
27
  import { InlineActivityComposer } from '../../../../components/detail/InlineActivityComposer'
28
28
  import { PipelineStepper } from '../../../../components/detail/PipelineStepper'
29
29
  import { PlannedActivitiesSection } from '../../../../components/detail/PlannedActivitiesSection'
30
- import { ScheduleActivityDialog } from '../../../../components/detail/ScheduleActivityDialog'
30
+ import { ScheduleActivityDialog, type ScheduleActivityEditData } from '../../../../components/detail/ScheduleActivityDialog'
31
31
  import { createCustomerNotesAdapter } from '../../../../components/detail/notesAdapter'
32
32
  import type { InteractionSummary } from '../../../../components/detail/types'
33
33
  import { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '../../../../lib/markdownPreference'
@@ -220,12 +220,18 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
220
220
  if (activity.entityId && activityEntities.some((entry) => entry.id === activity.entityId)) {
221
221
  setSelectedActivityEntityId(activity.entityId)
222
222
  }
223
+ // Forward `customValues` so per-type chip state (callPhoneNumber,
224
+ // callDirection, taskPriority) round-trips on edit (#1808 phone persistence).
225
+ // Forward `occurredAt` so historical activity edits prefill from the
226
+ // original moment instead of "today" (#1807 prefill).
227
+ const rawActivity = activity as unknown as Record<string, unknown>
223
228
  openScheduleEdit({
224
229
  id: activity.id,
225
230
  interactionType: activity.interactionType,
226
231
  title: activity.title ?? null,
227
232
  body: activity.body ?? null,
228
233
  scheduledAt: activity.scheduledAt ?? null,
234
+ occurredAt: activity.occurredAt ?? null,
229
235
  durationMinutes: activity.duration ?? null,
230
236
  location: activity.location ?? null,
231
237
  allDay: activity.allDay ?? null,
@@ -236,7 +242,13 @@ export default function DealDetailPage({ params }: { params?: { id?: string } })
236
242
  visibility: activity.visibility ?? null,
237
243
  linkedEntities: activity.linkedEntities ?? null,
238
244
  guestPermissions: activity.guestPermissions ?? null,
239
- })
245
+ ...(rawActivity.customValues && typeof rawActivity.customValues === 'object'
246
+ ? { customValues: rawActivity.customValues as Record<string, unknown> }
247
+ : {}),
248
+ ...(typeof rawActivity.phoneNumber === 'string'
249
+ ? { phoneNumber: rawActivity.phoneNumber as string }
250
+ : {}),
251
+ } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null })
240
252
  }, [activityEntities, openScheduleEdit])
241
253
 
242
254
  const handleViewDashboard = React.useCallback(() => {
@@ -210,19 +210,24 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
210
210
  setScheduleDialogOpen(true)
211
211
  }, [])
212
212
 
213
- const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; [key: string]: unknown }) => {
213
+ const handleEditActivity = React.useCallback((activity: { id: string; interactionType?: string; title?: string | null; body?: string | null; scheduledAt?: string | null; occurredAt?: string | null; [key: string]: unknown }) => {
214
214
  const raw = activity as Record<string, unknown>
215
215
  const durationValue = typeof raw.duration === 'number'
216
216
  ? raw.duration
217
217
  : typeof raw.durationMinutes === 'number'
218
218
  ? raw.durationMinutes as number
219
219
  : null
220
- setScheduleEditData({
220
+ // Forward `customValues` so per-type chip state (callPhoneNumber, callDirection,
221
+ // taskPriority, …) round-trips on edit (#1808 phone persistence).
222
+ // Forward `occurredAt` so historical activity edits prefill from the original
223
+ // moment instead of "today" (#1807 prefill).
224
+ const editPayload = {
221
225
  id: activity.id,
222
226
  interactionType: typeof activity.interactionType === 'string' ? activity.interactionType : undefined,
223
227
  title: typeof activity.title === 'string' ? activity.title : null,
224
228
  body: typeof activity.body === 'string' ? activity.body : null,
225
229
  scheduledAt: typeof activity.scheduledAt === 'string' ? activity.scheduledAt : null,
230
+ occurredAt: typeof activity.occurredAt === 'string' ? activity.occurredAt : null,
226
231
  durationMinutes: durationValue,
227
232
  location: typeof raw.location === 'string' ? raw.location as string : null,
228
233
  allDay: typeof raw.allDay === 'boolean' ? raw.allDay as boolean : null,
@@ -235,7 +240,12 @@ export default function PersonDetailV2Page({ params }: { params?: { id?: string
235
240
  guestPermissions: raw.guestPermissions && typeof raw.guestPermissions === 'object'
236
241
  ? raw.guestPermissions as ScheduleActivityEditData['guestPermissions']
237
242
  : null,
238
- })
243
+ customValues: raw.customValues && typeof raw.customValues === 'object'
244
+ ? raw.customValues as Record<string, unknown>
245
+ : null,
246
+ phoneNumber: typeof raw.phoneNumber === 'string' ? raw.phoneNumber as string : null,
247
+ } as ScheduleActivityEditData & { customValues?: Record<string, unknown> | null; phoneNumber?: string | null }
248
+ setScheduleEditData(editPayload)
239
249
  setScheduleDialogOpen(true)
240
250
  }, [])
241
251