@open-mercato/core 0.10.1-develop.7717.1.2befe9c634 → 0.10.1-develop.7721.1.b5c4a00a68
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/staff_support_routing_rule/index.js +21 -0
- package/dist/generated/entities/staff_support_routing_rule/index.js.map +7 -0
- package/dist/generated/entities/staff_support_ticket/index.js +37 -0
- package/dist/generated/entities/staff_support_ticket/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project/index.js +2 -0
- package/dist/generated/entities/staff_time_project/index.js.map +2 -2
- package/dist/generated/entities/staff_time_project_member/index.js +2 -0
- package/dist/generated/entities/staff_time_project_member/index.js.map +2 -2
- package/dist/generated/entities/staff_time_task/index.js +4 -0
- package/dist/generated/entities/staff_time_task/index.js.map +2 -2
- package/dist/generated/entities/staff_time_task_comment/index.js +9 -1
- package/dist/generated/entities/staff_time_task_comment/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +2 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +38 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/auth.js +1 -0
- package/dist/helpers/integration/auth.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +20 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/catalog/api/bulk-delete/route.js +12 -2
- package/dist/modules/catalog/api/bulk-delete/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +17 -3
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/lib/test-seed.js +38 -5
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +2 -3
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js +299 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js +91 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/route.js +146 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/options/route.js +60 -0
- package/dist/modules/staff/api/portal/support-tickets/options/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/route.js +220 -0
- package/dist/modules/staff/api/portal/support-tickets/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/route.js +7 -1
- package/dist/modules/staff/api/timesheets/settings/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js +122 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js +180 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/route.js +147 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-tickets/options/route.js +133 -0
- package/dist/modules/staff/api/timesheets/support-tickets/options/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js +33 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +25 -7
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js +32 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js +94 -47
- package/dist/modules/staff/api/timesheets/tasks/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +3 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/route.js +3 -0
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +1 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +54 -4
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +21 -5
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +319 -254
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/support/page.js +363 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js.map +7 -0
- package/dist/modules/staff/cli.js +27 -0
- package/dist/modules/staff/cli.js.map +2 -2
- package/dist/modules/staff/commands/index.js +3 -0
- package/dist/modules/staff/commands/index.js.map +2 -2
- package/dist/modules/staff/commands/shared.js +10 -1
- package/dist/modules/staff/commands/shared.js.map +2 -2
- package/dist/modules/staff/commands/support-routing-rules.js +505 -0
- package/dist/modules/staff/commands/support-routing-rules.js.map +7 -0
- package/dist/modules/staff/commands/support-tickets.js +513 -0
- package/dist/modules/staff/commands/support-tickets.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-projects.js +72 -14
- package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-task-assignment.js +270 -0
- package/dist/modules/staff/commands/timesheets-task-assignment.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js +58 -12
- package/dist/modules/staff/commands/timesheets-task-comments.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-tasks.js +91 -9
- package/dist/modules/staff/commands/timesheets-tasks.js.map +3 -3
- package/dist/modules/staff/data/enrichers.js +141 -0
- package/dist/modules/staff/data/enrichers.js.map +2 -2
- package/dist/modules/staff/data/entities.js +143 -2
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/staff/data/extensions.js +8 -0
- package/dist/modules/staff/data/extensions.js.map +2 -2
- package/dist/modules/staff/data/validators.js +34 -5
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/encryption.js +6 -0
- package/dist/modules/staff/encryption.js.map +2 -2
- package/dist/modules/staff/events.js +25 -0
- package/dist/modules/staff/events.js.map +2 -2
- package/dist/modules/staff/events.payloads.js +54 -0
- package/dist/modules/staff/events.payloads.js.map +2 -2
- package/dist/modules/staff/extension-points.js +1 -0
- package/dist/modules/staff/extension-points.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js +468 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js +316 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js +190 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js +19 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js.map +7 -0
- package/dist/modules/staff/index.js +1 -1
- package/dist/modules/staff/index.js.map +2 -2
- package/dist/modules/staff/lib/crud.js +2 -0
- package/dist/modules/staff/lib/crud.js.map +2 -2
- package/dist/modules/staff/lib/support/attachments.js +36 -0
- package/dist/modules/staff/lib/support/attachments.js.map +7 -0
- package/dist/modules/staff/lib/support/dictionaries.js +87 -0
- package/dist/modules/staff/lib/support/dictionaries.js.map +7 -0
- package/dist/modules/staff/lib/support/notifications.js +111 -0
- package/dist/modules/staff/lib/support/notifications.js.map +7 -0
- package/dist/modules/staff/lib/support/portalAttachments.js +100 -0
- package/dist/modules/staff/lib/support/portalAttachments.js.map +7 -0
- package/dist/modules/staff/lib/support/portalBroadcast.js +117 -0
- package/dist/modules/staff/lib/support/portalBroadcast.js.map +7 -0
- package/dist/modules/staff/lib/support/portalRoute.js +99 -0
- package/dist/modules/staff/lib/support/portalRoute.js.map +7 -0
- package/dist/modules/staff/lib/support/portalStatus.js +12 -0
- package/dist/modules/staff/lib/support/portalStatus.js.map +7 -0
- package/dist/modules/staff/lib/support/portalTickets.js +148 -0
- package/dist/modules/staff/lib/support/portalTickets.js.map +7 -0
- package/dist/modules/staff/lib/support/routing.js +81 -0
- package/dist/modules/staff/lib/support/routing.js.map +7 -0
- package/dist/modules/staff/lib/support/routingRuleDraft.js +25 -0
- package/dist/modules/staff/lib/support/routingRuleDraft.js.map +7 -0
- package/dist/modules/staff/lib/support/seedDefaults.js +114 -0
- package/dist/modules/staff/lib/support/seedDefaults.js.map +7 -0
- package/dist/modules/staff/lib/support/supportActivity.js +26 -0
- package/dist/modules/staff/lib/support/supportActivity.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js +23 -0
- package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js +112 -0
- package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalPendingUploads.js +45 -0
- package/dist/modules/staff/lib/support-ui/portalPendingUploads.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalSupport.js +51 -0
- package/dist/modules/staff/lib/support-ui/portalSupport.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/access.js +3 -39
- package/dist/modules/staff/lib/time-tracking/access.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/listProjectAccess.js +54 -0
- package/dist/modules/staff/lib/time-tracking/listProjectAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js +92 -2
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/projectAssignment.js +112 -0
- package/dist/modules/staff/lib/time-tracking/projectAssignment.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js +14 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/settings.js +28 -1
- package/dist/modules/staff/lib/time-tracking/settings.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js +143 -0
- package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/workRecipients.js +92 -0
- package/dist/modules/staff/lib/time-tracking/workRecipients.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +32 -3
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +29 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +4 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +141 -1
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js +153 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js +67 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +3 -1
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +80 -17
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +230 -41
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +21 -1
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +16 -4
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +3 -1
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js +68 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js +50 -0
- package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +13 -1
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +36 -2
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +2 -2
- package/dist/modules/staff/migrations/Migration20261009180543_staff.js +42 -0
- package/dist/modules/staff/migrations/Migration20261009180543_staff.js.map +7 -0
- package/dist/modules/staff/notifications.js +92 -0
- package/dist/modules/staff/notifications.js.map +2 -2
- package/dist/modules/staff/setup.js +6 -2
- package/dist/modules/staff/setup.js.map +2 -2
- package/dist/modules/staff/subscribers/support-portal-comment-created.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-created.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-comment-deleted.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-deleted.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-comment-updated.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-status-column-updated.js +24 -0
- package/dist/modules/staff/subscribers/support-portal-status-column-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-task-status-changed.js +25 -0
- package/dist/modules/staff/subscribers/support-portal-task-status-changed.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-task-updated.js +25 -0
- package/dist/modules/staff/subscribers/support-portal-task-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-created-notification.js +25 -0
- package/dist/modules/staff/subscribers/support-ticket-created-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js +25 -0
- package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js +26 -0
- package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js.map +7 -0
- package/dist/modules/staff/subscribers/time-task-assignee-notification.js +83 -0
- package/dist/modules/staff/subscribers/time-task-assignee-notification.js.map +7 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js +112 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js +17 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js +870 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js +17 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection-table.js +16 -1
- package/dist/modules/staff/widgets/injection-table.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
- package/dist/modules/wms/lib/inventoryCsvExport.js +19 -0
- package/dist/modules/wms/lib/inventoryCsvExport.js.map +7 -0
- package/generated/entities/staff_support_routing_rule/index.ts +9 -0
- package/generated/entities/staff_support_ticket/index.ts +17 -0
- package/generated/entities/staff_time_project/index.ts +1 -0
- package/generated/entities/staff_time_project_member/index.ts +1 -0
- package/generated/entities/staff_time_task/index.ts +2 -0
- package/generated/entities/staff_time_task_comment/index.ts +4 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +38 -0
- package/package.json +8 -8
- package/src/helpers/integration/auth.ts +1 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +60 -2
- package/src/modules/catalog/api/bulk-delete/route.ts +12 -2
- package/src/modules/communication_channels/api/post/test-seed/route.ts +29 -12
- package/src/modules/communication_channels/lib/test-seed.ts +49 -10
- package/src/modules/messages/commands/messages.ts +8 -10
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +2 -2
- package/src/modules/staff/AGENTS.md +22 -6
- package/src/modules/staff/api/portal/support-tickets/[id]/attachments/route.ts +327 -0
- package/src/modules/staff/api/portal/support-tickets/[id]/messages/route.ts +94 -0
- package/src/modules/staff/api/portal/support-tickets/[id]/route.ts +160 -0
- package/src/modules/staff/api/portal/support-tickets/options/route.ts +60 -0
- package/src/modules/staff/api/portal/support-tickets/route.ts +253 -0
- package/src/modules/staff/api/timesheets/settings/route.ts +7 -1
- package/src/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.ts +131 -0
- package/src/modules/staff/api/timesheets/support-routing-rules/preview/route.ts +248 -0
- package/src/modules/staff/api/timesheets/support-routing-rules/route.ts +150 -0
- package/src/modules/staff/api/timesheets/support-tickets/options/route.ts +181 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/claim/route.ts +31 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +25 -7
- package/src/modules/staff/api/timesheets/tasks/[id]/release/route.ts +30 -0
- package/src/modules/staff/api/timesheets/tasks/route.ts +119 -67
- package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +3 -0
- package/src/modules/staff/api/timesheets/time-projects/route.ts +3 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +1 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +67 -2
- package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +22 -3
- package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +405 -308
- package/src/modules/staff/backend/staff/time-tracking/support/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/support/page.tsx +428 -0
- package/src/modules/staff/cli.ts +28 -0
- package/src/modules/staff/commands/index.ts +3 -0
- package/src/modules/staff/commands/shared.ts +22 -1
- package/src/modules/staff/commands/support-routing-rules.ts +595 -0
- package/src/modules/staff/commands/support-tickets.ts +580 -0
- package/src/modules/staff/commands/timesheets-projects.ts +84 -13
- package/src/modules/staff/commands/timesheets-task-assignment.ts +319 -0
- package/src/modules/staff/commands/timesheets-task-comments.ts +70 -15
- package/src/modules/staff/commands/timesheets-tasks.ts +106 -15
- package/src/modules/staff/data/enrichers.ts +203 -0
- package/src/modules/staff/data/entities.ts +133 -2
- package/src/modules/staff/data/extensions.ts +9 -1
- package/src/modules/staff/data/validators.ts +36 -0
- package/src/modules/staff/encryption.ts +6 -0
- package/src/modules/staff/events.payloads.ts +87 -1
- package/src/modules/staff/events.ts +26 -0
- package/src/modules/staff/extension-points.ts +1 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.tsx +553 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.tsx +346 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/page.meta.ts +17 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/page.tsx +253 -0
- package/src/modules/staff/i18n/de.json +291 -0
- package/src/modules/staff/i18n/en.json +291 -0
- package/src/modules/staff/i18n/es.json +291 -0
- package/src/modules/staff/i18n/ko.json +291 -0
- package/src/modules/staff/i18n/pl.json +291 -0
- package/src/modules/staff/index.ts +1 -1
- package/src/modules/staff/lib/crud.ts +2 -1
- package/src/modules/staff/lib/support/attachments.ts +43 -0
- package/src/modules/staff/lib/support/dictionaries.ts +120 -0
- package/src/modules/staff/lib/support/notifications.ts +138 -0
- package/src/modules/staff/lib/support/portalAttachments.ts +140 -0
- package/src/modules/staff/lib/support/portalBroadcast.ts +161 -0
- package/src/modules/staff/lib/support/portalRoute.ts +108 -0
- package/src/modules/staff/lib/support/portalStatus.ts +15 -0
- package/src/modules/staff/lib/support/portalTickets.ts +233 -0
- package/src/modules/staff/lib/support/routing.ts +117 -0
- package/src/modules/staff/lib/support/routingRuleDraft.ts +45 -0
- package/src/modules/staff/lib/support/seedDefaults.ts +151 -0
- package/src/modules/staff/lib/support/supportActivity.ts +39 -0
- package/src/modules/staff/lib/support-ui/PortalSupportNotLinked.tsx +20 -0
- package/src/modules/staff/lib/support-ui/portalAttachmentValidation.ts +125 -0
- package/src/modules/staff/lib/support-ui/portalPendingUploads.ts +49 -0
- package/src/modules/staff/lib/support-ui/portalSupport.ts +116 -0
- package/src/modules/staff/lib/time-tracking/access.ts +2 -62
- package/src/modules/staff/lib/time-tracking/listProjectAccess.ts +78 -0
- package/src/modules/staff/lib/time-tracking/portalRecipients.ts +173 -5
- package/src/modules/staff/lib/time-tracking/projectAssignment.ts +172 -0
- package/src/modules/staff/lib/time-tracking/settingKeys.ts +11 -0
- package/src/modules/staff/lib/time-tracking/settings.ts +46 -1
- package/src/modules/staff/lib/time-tracking/taskAssignmentRoute.ts +165 -0
- package/src/modules/staff/lib/time-tracking/workRecipients.ts +183 -0
- package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +36 -1
- package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +30 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +9 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +185 -6
- package/src/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.tsx +188 -0
- package/src/modules/staff/lib/time-tracking-ui/SupportRequestPanel.tsx +102 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +2 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +105 -22
- package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +278 -43
- package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +21 -0
- package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +16 -2
- package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +4 -0
- package/src/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.ts +117 -0
- package/src/modules/staff/lib/time-tracking-ui/settingsTabs.ts +17 -0
- package/src/modules/staff/lib/time-tracking-ui/supportTicketData.ts +71 -0
- package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +15 -0
- package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +48 -1
- package/src/modules/staff/migrations/.snapshot-open-mercato.json +714 -0
- package/src/modules/staff/migrations/Migration20261009180543_staff.ts +50 -0
- package/src/modules/staff/notifications.ts +92 -0
- package/src/modules/staff/setup.ts +6 -2
- package/src/modules/staff/subscribers/support-portal-comment-created.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-comment-deleted.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-comment-updated.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-status-column-updated.ts +36 -0
- package/src/modules/staff/subscribers/support-portal-task-status-changed.ts +34 -0
- package/src/modules/staff/subscribers/support-portal-task-updated.ts +34 -0
- package/src/modules/staff/subscribers/support-ticket-created-notification.ts +27 -0
- package/src/modules/staff/subscribers/support-ticket-customer-replied-notification.ts +27 -0
- package/src/modules/staff/subscribers/support-ticket-unnotified-clear.ts +29 -0
- package/src/modules/staff/subscribers/time-task-assignee-notification.ts +102 -0
- package/src/modules/staff/widgets/injection/portal-support-tickets/widget.client.tsx +151 -0
- package/src/modules/staff/widgets/injection/portal-support-tickets/widget.ts +16 -0
- package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.tsx +1058 -0
- package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.ts +17 -0
- package/src/modules/staff/widgets/injection-table.ts +15 -0
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +4 -20
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +4 -20
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +4 -19
- package/src/modules/wms/lib/inventoryCsvExport.ts +18 -0
|
@@ -5,11 +5,13 @@ import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacS
|
|
|
5
5
|
import { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
6
6
|
import { CustomerEntity } from '@open-mercato/core/modules/customers/data/entities'
|
|
7
7
|
import {
|
|
8
|
+
StaffSupportTicket,
|
|
8
9
|
StaffTeamMember,
|
|
9
10
|
StaffTimeProject,
|
|
10
11
|
StaffTimeReport,
|
|
11
12
|
StaffTimeReportEntry,
|
|
12
13
|
StaffTimeReportEvent,
|
|
14
|
+
StaffTimeProjectMember,
|
|
13
15
|
StaffTimeTask,
|
|
14
16
|
StaffTimeTaskStatus,
|
|
15
17
|
} from './entities'
|
|
@@ -22,8 +24,15 @@ import {
|
|
|
22
24
|
type MemberPreview,
|
|
23
25
|
} from '../lib/timesheets-projects/listProjectMembersPreview'
|
|
24
26
|
import { computeTaskRollups, EMPTY_TASK_ROLLUP } from '../lib/timesheets-tasks/computeTaskRollups'
|
|
27
|
+
import { derivePortalStatus } from '../lib/support/portalStatus'
|
|
28
|
+
import {
|
|
29
|
+
isActiveAssignment,
|
|
30
|
+
normalizeAssignmentGraceDays,
|
|
31
|
+
resolveAssignmentGraceDaysFromContainer,
|
|
32
|
+
} from '../lib/time-tracking/projectAssignment'
|
|
25
33
|
|
|
26
34
|
const MANAGE_FEATURE = 'staff.timesheets.projects.manage'
|
|
35
|
+
const TASKS_VIEW_FEATURE = 'staff.timesheets.tasks.view'
|
|
27
36
|
const RATES_FEATURE = 'staff.timesheets.rates.view'
|
|
28
37
|
|
|
29
38
|
/**
|
|
@@ -635,6 +644,198 @@ const taskContextEnricher: ResponseEnricher<EntityRecord, TaskContextEnrichment>
|
|
|
635
644
|
},
|
|
636
645
|
}
|
|
637
646
|
|
|
647
|
+
export type SupportTicketEnrichment = {
|
|
648
|
+
_staffSupport: {
|
|
649
|
+
ticket: {
|
|
650
|
+
id: string
|
|
651
|
+
supportReference: string
|
|
652
|
+
category: { value: string; label: string }
|
|
653
|
+
routedVia: string
|
|
654
|
+
portalStatus: string
|
|
655
|
+
customerSnapshot: Record<string, unknown> | null
|
|
656
|
+
reportedByCustomerUserId: string | null
|
|
657
|
+
unnotifiedAt: string | null
|
|
658
|
+
customerRequest: { subject: string; body: string } | null
|
|
659
|
+
} | null
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const EMPTY_SUPPORT_TICKET: SupportTicketEnrichment = { _staffSupport: { ticket: null } }
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* The customer request behind a portal ticket. Internal tasks get `ticket: null`.
|
|
667
|
+
* `customerRequest` is the encrypted original the portal shows, read here so the
|
|
668
|
+
* drawer can show staff exactly what the customer sees.
|
|
669
|
+
*/
|
|
670
|
+
const supportTicketEnricher: ResponseEnricher<EntityRecord, SupportTicketEnrichment> = {
|
|
671
|
+
id: 'staff.timesheets-tasks-support-ticket',
|
|
672
|
+
targetEntity: 'staff:staff_time_task',
|
|
673
|
+
priority: 4,
|
|
674
|
+
timeout: 3000,
|
|
675
|
+
critical: false,
|
|
676
|
+
fallback: { ...EMPTY_SUPPORT_TICKET },
|
|
677
|
+
cacheableOnListHit: false,
|
|
678
|
+
|
|
679
|
+
async enrichOne(record, context) {
|
|
680
|
+
const enriched = await this.enrichMany!([record], context)
|
|
681
|
+
return enriched[0]
|
|
682
|
+
},
|
|
683
|
+
|
|
684
|
+
async enrichMany(records, context) {
|
|
685
|
+
if (records.length === 0) return records as (EntityRecord & SupportTicketEnrichment)[]
|
|
686
|
+
const ctx = context as InternalContext
|
|
687
|
+
if (!ctx.tenantId || !ctx.organizationId) {
|
|
688
|
+
return records.map((record) => ({ ...record, ...EMPTY_SUPPORT_TICKET }))
|
|
689
|
+
}
|
|
690
|
+
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
691
|
+
const portalRecordIds = records
|
|
692
|
+
.filter((record) => record.source === 'portal' || record.source === undefined)
|
|
693
|
+
.map((record) => record.id)
|
|
694
|
+
.filter((id): id is string => typeof id === 'string')
|
|
695
|
+
if (portalRecordIds.length === 0) {
|
|
696
|
+
return records.map((record) => ({ ...record, ...EMPTY_SUPPORT_TICKET }))
|
|
697
|
+
}
|
|
698
|
+
const tickets = await findWithDecryption(
|
|
699
|
+
ctx.em.fork(),
|
|
700
|
+
StaffSupportTicket,
|
|
701
|
+
{ taskId: { $in: portalRecordIds }, ...scope, deletedAt: null },
|
|
702
|
+
undefined,
|
|
703
|
+
scope,
|
|
704
|
+
)
|
|
705
|
+
if (tickets.length === 0) {
|
|
706
|
+
return records.map((record) => ({ ...record, ...EMPTY_SUPPORT_TICKET }))
|
|
707
|
+
}
|
|
708
|
+
const ticketByTask = new Map(tickets.map((ticket) => [ticket.taskId, ticket]))
|
|
709
|
+
const tasks = await ctx.em.fork().find(
|
|
710
|
+
StaffTimeTask,
|
|
711
|
+
{ id: { $in: tickets.map((ticket) => ticket.taskId) }, ...scope },
|
|
712
|
+
{ fields: ['id', 'taskStatusId'] },
|
|
713
|
+
)
|
|
714
|
+
const statusIds = [...new Set(tasks.map((task) => task.taskStatusId))]
|
|
715
|
+
const statuses = statusIds.length
|
|
716
|
+
? await ctx.em.fork().find(StaffTimeTaskStatus, { id: { $in: statusIds }, ...scope }, { fields: ['id', 'isDefault', 'isDone'] })
|
|
717
|
+
: []
|
|
718
|
+
const statusById = new Map(statuses.map((status) => [status.id, status]))
|
|
719
|
+
const statusByTask = new Map(tasks.map((task) => [task.id, statusById.get(task.taskStatusId) ?? null]))
|
|
720
|
+
|
|
721
|
+
return records.map((record) => {
|
|
722
|
+
const ticket = typeof record.id === 'string' ? ticketByTask.get(record.id) : undefined
|
|
723
|
+
if (!ticket) return { ...record, ...EMPTY_SUPPORT_TICKET }
|
|
724
|
+
const request = ticket.customerRequestSnapshot
|
|
725
|
+
return {
|
|
726
|
+
...record,
|
|
727
|
+
_staffSupport: {
|
|
728
|
+
ticket: {
|
|
729
|
+
id: ticket.id,
|
|
730
|
+
supportReference: ticket.supportReference,
|
|
731
|
+
category: ticket.categorySnapshot,
|
|
732
|
+
routedVia: ticket.routedVia,
|
|
733
|
+
portalStatus: derivePortalStatus(statusByTask.get(ticket.taskId) ?? null),
|
|
734
|
+
customerSnapshot: ticket.customerSnapshot ?? null,
|
|
735
|
+
reportedByCustomerUserId: ticket.reportedByCustomerUserId ?? null,
|
|
736
|
+
unnotifiedAt: ticket.unnotifiedAt ? ticket.unnotifiedAt.toISOString() : null,
|
|
737
|
+
customerRequest:
|
|
738
|
+
request && typeof request === 'object' && typeof request.subject === 'string'
|
|
739
|
+
? { subject: request.subject, body: typeof request.body === 'string' ? request.body : '' }
|
|
740
|
+
: null,
|
|
741
|
+
},
|
|
742
|
+
},
|
|
743
|
+
}
|
|
744
|
+
})
|
|
745
|
+
},
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Whether the CALLER may claim or release each task right now, decided by the same
|
|
750
|
+
* rule the claim and release commands enforce: claiming needs an active assigner
|
|
751
|
+
* membership of the task's project inside its assignment window (plus the tenant's
|
|
752
|
+
* grace days), an unassigned task and a column that is not done; releasing needs the
|
|
753
|
+
* caller to be the current assignee. The drawer reads these instead of guessing from
|
|
754
|
+
* a page of project members, so it never offers an action the server refuses.
|
|
755
|
+
*/
|
|
756
|
+
export type TaskAssignmentEnrichment = {
|
|
757
|
+
_staffAssignment: {
|
|
758
|
+
canClaim: boolean
|
|
759
|
+
canRelease: boolean
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
const NO_TASK_ASSIGNMENT: TaskAssignmentEnrichment = { _staffAssignment: { canClaim: false, canRelease: false } }
|
|
764
|
+
|
|
765
|
+
const taskAssignmentEnricher: ResponseEnricher<EntityRecord, TaskAssignmentEnrichment> = {
|
|
766
|
+
id: 'staff.timesheets-tasks-assignment',
|
|
767
|
+
targetEntity: 'staff:staff_time_task',
|
|
768
|
+
features: [TASKS_VIEW_FEATURE],
|
|
769
|
+
priority: 3,
|
|
770
|
+
timeout: 3000,
|
|
771
|
+
critical: false,
|
|
772
|
+
fallback: { ...NO_TASK_ASSIGNMENT },
|
|
773
|
+
cacheableOnListHit: false,
|
|
774
|
+
|
|
775
|
+
async enrichOne(record, context) {
|
|
776
|
+
const enriched = await this.enrichMany!([record], context)
|
|
777
|
+
return enriched[0]
|
|
778
|
+
},
|
|
779
|
+
|
|
780
|
+
async enrichMany(records, context) {
|
|
781
|
+
if (records.length === 0) return records as (EntityRecord & TaskAssignmentEnrichment)[]
|
|
782
|
+
const ctx = context as InternalContext
|
|
783
|
+
if (!ctx.tenantId || !ctx.organizationId || !ctx.userId) {
|
|
784
|
+
return records.map((record) => ({ ...record, ...NO_TASK_ASSIGNMENT }))
|
|
785
|
+
}
|
|
786
|
+
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
787
|
+
const callerStaffMemberId = await resolveCallerStaffMemberId(ctx)
|
|
788
|
+
if (!callerStaffMemberId) return records.map((record) => ({ ...record, ...NO_TASK_ASSIGNMENT }))
|
|
789
|
+
|
|
790
|
+
const taskIds = records.map((record) => record.id).filter((id): id is string => typeof id === 'string')
|
|
791
|
+
const tasks = await ctx.em.fork().find(
|
|
792
|
+
StaffTimeTask,
|
|
793
|
+
{ id: { $in: taskIds }, ...scope, deletedAt: null },
|
|
794
|
+
{ fields: ['id', 'timeProjectId', 'taskStatusId', 'assigneeStaffMemberId'] },
|
|
795
|
+
)
|
|
796
|
+
const taskById = new Map(tasks.map((task) => [task.id, task]))
|
|
797
|
+
const projectIds = [...new Set(tasks.map((task) => task.timeProjectId).filter(Boolean))]
|
|
798
|
+
const statusIds = [...new Set(tasks.map((task) => task.taskStatusId).filter(Boolean))]
|
|
799
|
+
|
|
800
|
+
const [statuses, memberships, graceDays] = await Promise.all([
|
|
801
|
+
statusIds.length
|
|
802
|
+
? ctx.em.fork().find(StaffTimeTaskStatus, { id: { $in: statusIds }, ...scope }, { fields: ['id', 'isDone'] })
|
|
803
|
+
: Promise.resolve([]),
|
|
804
|
+
projectIds.length
|
|
805
|
+
? ctx.em.fork().find(StaffTimeProjectMember, {
|
|
806
|
+
timeProjectId: { $in: projectIds },
|
|
807
|
+
staffMemberId: callerStaffMemberId,
|
|
808
|
+
isAssigner: true,
|
|
809
|
+
status: 'active',
|
|
810
|
+
deletedAt: null,
|
|
811
|
+
...scope,
|
|
812
|
+
})
|
|
813
|
+
: Promise.resolve([]),
|
|
814
|
+
resolveAssignmentGraceDaysFromContainer(ctx.container, ctx.tenantId),
|
|
815
|
+
])
|
|
816
|
+
const doneStatusIds = new Set(statuses.filter((status) => status.isDone).map((status) => status.id))
|
|
817
|
+
const now = new Date()
|
|
818
|
+
const assignerProjectIds = new Set(
|
|
819
|
+
memberships
|
|
820
|
+
.filter((membership) => isActiveAssignment(membership, now, normalizeAssignmentGraceDays(graceDays)))
|
|
821
|
+
.map((membership) => membership.timeProjectId),
|
|
822
|
+
)
|
|
823
|
+
|
|
824
|
+
return records.map((record) => {
|
|
825
|
+
const task = taskById.get(record.id)
|
|
826
|
+
if (!task) return { ...record, ...NO_TASK_ASSIGNMENT }
|
|
827
|
+
const assignee = task.assigneeStaffMemberId ?? null
|
|
828
|
+
return {
|
|
829
|
+
...record,
|
|
830
|
+
_staffAssignment: {
|
|
831
|
+
canClaim: !assignee && assignerProjectIds.has(task.timeProjectId) && !doneStatusIds.has(task.taskStatusId),
|
|
832
|
+
canRelease: assignee === callerStaffMemberId,
|
|
833
|
+
},
|
|
834
|
+
}
|
|
835
|
+
})
|
|
836
|
+
},
|
|
837
|
+
}
|
|
838
|
+
|
|
638
839
|
/**
|
|
639
840
|
* What a report row cannot say about itself: whether it is frozen, how many entries
|
|
640
841
|
* the freeze holds, and whether anyone has taken a file out of it.
|
|
@@ -787,6 +988,8 @@ const apiEnrichers: ResponseEnricher[] = [
|
|
|
787
988
|
taskRollupEnricher,
|
|
788
989
|
taskTagEnricher,
|
|
789
990
|
taskContextEnricher,
|
|
991
|
+
supportTicketEnricher,
|
|
992
|
+
taskAssignmentEnricher,
|
|
790
993
|
timeEntryEnricher,
|
|
791
994
|
reportEnricher,
|
|
792
995
|
]
|
|
@@ -376,6 +376,11 @@ export class StaffTeamMemberAddress {
|
|
|
376
376
|
export type StaffTimeEntrySource = TimeEntrySource
|
|
377
377
|
export type StaffTimeProjectStatus = 'active' | 'on_hold' | 'completed'
|
|
378
378
|
export type StaffTimeProjectMemberStatus = 'active' | 'inactive'
|
|
379
|
+
export type StaffTimeTaskSource = 'internal' | 'portal'
|
|
380
|
+
export type StaffTimeTaskCommentVisibility = 'internal' | 'customer'
|
|
381
|
+
export type StaffTimeTaskCommentAuthorKind = 'staff' | 'customer'
|
|
382
|
+
export type StaffSupportRoutedVia = 'category' | 'fallback'
|
|
383
|
+
export type StaffSupportPortalStatus = 'received' | 'in_progress' | 'resolved'
|
|
379
384
|
export type StaffTimeEntrySegmentType = 'work' | 'break'
|
|
380
385
|
export type StaffTimeProjectBudgetKind = 'none' | 'hours' | 'amount'
|
|
381
386
|
export type StaffTimeReportPeriodKind = 'week' | 'month' | 'year' | 'custom'
|
|
@@ -572,6 +577,9 @@ export class StaffTimeProject {
|
|
|
572
577
|
@Property({ name: 'budget_alerted_at_percent', type: 'integer', nullable: true })
|
|
573
578
|
budgetAlertedAtPercent?: number | null
|
|
574
579
|
|
|
580
|
+
@Property({ name: 'default_assignee_staff_member_id', type: 'uuid', nullable: true })
|
|
581
|
+
defaultAssigneeStaffMemberId?: string | null
|
|
582
|
+
|
|
575
583
|
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
576
584
|
createdAt: Date = new Date()
|
|
577
585
|
|
|
@@ -587,7 +595,10 @@ export class StaffTimeProject {
|
|
|
587
595
|
@Index({ name: 'staff_time_project_members_project_idx', properties: ['organizationId', 'timeProjectId'] })
|
|
588
596
|
@Index({ name: 'staff_time_project_members_member_idx', properties: ['organizationId', 'staffMemberId'] })
|
|
589
597
|
@Index({ name: 'staff_time_project_members_unique_idx', properties: ['organizationId', 'tenantId', 'timeProjectId', 'staffMemberId'], options: { unique: true, where: 'deleted_at IS NULL' } })
|
|
598
|
+
@Index({ name: 'staff_time_project_members_assigner_idx', properties: ['tenantId', 'organizationId', 'timeProjectId'], options: { where: "is_assigner = true AND status = 'active' AND deleted_at IS NULL" } })
|
|
590
599
|
export class StaffTimeProjectMember {
|
|
600
|
+
[OptionalProps]?: 'status' | 'showInGrid' | 'isAssigner' | 'createdAt' | 'updatedAt'
|
|
601
|
+
|
|
591
602
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
592
603
|
id!: string
|
|
593
604
|
|
|
@@ -612,6 +623,9 @@ export class StaffTimeProjectMember {
|
|
|
612
623
|
@Property({ name: 'show_in_grid', type: 'boolean', default: false })
|
|
613
624
|
showInGrid: boolean = false
|
|
614
625
|
|
|
626
|
+
@Property({ name: 'is_assigner', type: 'boolean', default: false })
|
|
627
|
+
isAssigner: boolean = false
|
|
628
|
+
|
|
615
629
|
@Property({ name: 'assigned_start_date', type: 'date' })
|
|
616
630
|
assignedStartDate!: Date
|
|
617
631
|
|
|
@@ -684,8 +698,9 @@ export class StaffTimeTaskStatus {
|
|
|
684
698
|
@Index({ name: 'staff_time_tasks_assignee_idx', properties: ['organizationId', 'assigneeStaffMemberId'] })
|
|
685
699
|
@Index({ name: 'staff_time_tasks_sequence_unique_idx', properties: ['organizationId', 'tenantId', 'timeProjectId', 'sequenceNumber'], options: { unique: true, where: 'deleted_at IS NULL' } })
|
|
686
700
|
@Index({ name: 'staff_time_tasks_reference_unique_idx', properties: ['organizationId', 'tenantId', 'reference'], options: { unique: true, where: 'deleted_at IS NULL' } })
|
|
701
|
+
@Index({ name: 'staff_time_tasks_portal_customer_idx', properties: ['tenantId', 'organizationId', 'customerId', 'updatedAt'], options: { where: "source = 'portal' AND deleted_at IS NULL" } })
|
|
687
702
|
export class StaffTimeTask {
|
|
688
|
-
[OptionalProps]?: 'sequenceNumber' | 'position' | 'createdAt' | 'updatedAt'
|
|
703
|
+
[OptionalProps]?: 'sequenceNumber' | 'position' | 'source' | 'createdAt' | 'updatedAt'
|
|
689
704
|
|
|
690
705
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
691
706
|
id!: string
|
|
@@ -729,6 +744,110 @@ export class StaffTimeTask {
|
|
|
729
744
|
@Property({ name: 'closed_at', type: Date, nullable: true })
|
|
730
745
|
closedAt?: Date | null
|
|
731
746
|
|
|
747
|
+
@Property({ type: 'text', default: 'internal' })
|
|
748
|
+
source: StaffTimeTaskSource = 'internal'
|
|
749
|
+
|
|
750
|
+
@Property({ name: 'customer_id', type: 'uuid', nullable: true })
|
|
751
|
+
customerId?: string | null
|
|
752
|
+
|
|
753
|
+
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
754
|
+
createdAt: Date = new Date()
|
|
755
|
+
|
|
756
|
+
@Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
|
|
757
|
+
updatedAt: Date = new Date()
|
|
758
|
+
|
|
759
|
+
@Property({ name: 'deleted_at', type: Date, nullable: true })
|
|
760
|
+
deletedAt?: Date | null
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
@Entity({ tableName: 'staff_support_tickets' })
|
|
764
|
+
@Index({ name: 'staff_support_tickets_tenant_org_idx', properties: ['tenantId', 'organizationId'] })
|
|
765
|
+
@Index({ name: 'staff_support_tickets_task_unique_idx', properties: ['tenantId', 'organizationId', 'taskId'], options: { unique: true, where: 'deleted_at IS NULL' } })
|
|
766
|
+
@Index({ name: 'staff_support_tickets_reference_unique_idx', properties: ['tenantId', 'organizationId', 'supportReference'], options: { unique: true, where: 'deleted_at IS NULL' } })
|
|
767
|
+
@Index({ name: 'staff_support_tickets_sequence_idx', properties: ['tenantId', 'organizationId', 'supportSequenceNumber'] })
|
|
768
|
+
export class StaffSupportTicket {
|
|
769
|
+
[OptionalProps]?: 'createdAt' | 'updatedAt'
|
|
770
|
+
|
|
771
|
+
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
772
|
+
id!: string
|
|
773
|
+
|
|
774
|
+
@Property({ name: 'tenant_id', type: 'uuid' })
|
|
775
|
+
tenantId!: string
|
|
776
|
+
|
|
777
|
+
@Property({ name: 'organization_id', type: 'uuid' })
|
|
778
|
+
organizationId!: string
|
|
779
|
+
|
|
780
|
+
@Property({ name: 'task_id', type: 'uuid' })
|
|
781
|
+
taskId!: string
|
|
782
|
+
|
|
783
|
+
@Property({ name: 'customer_snapshot', type: 'jsonb', nullable: true })
|
|
784
|
+
customerSnapshot?: Record<string, unknown> | null
|
|
785
|
+
|
|
786
|
+
@Property({ name: 'reported_by_customer_user_id', type: 'uuid', nullable: true })
|
|
787
|
+
reportedByCustomerUserId?: string | null
|
|
788
|
+
|
|
789
|
+
@Property({ name: 'support_reference', type: 'text' })
|
|
790
|
+
supportReference!: string
|
|
791
|
+
|
|
792
|
+
@Property({ name: 'support_sequence_number', type: 'integer' })
|
|
793
|
+
supportSequenceNumber!: number
|
|
794
|
+
|
|
795
|
+
@Property({ name: 'category_value', type: 'text' })
|
|
796
|
+
categoryValue!: string
|
|
797
|
+
|
|
798
|
+
@Property({ name: 'category_snapshot', type: 'jsonb' })
|
|
799
|
+
categorySnapshot!: { value: string; label: string }
|
|
800
|
+
|
|
801
|
+
@Property({ name: 'routed_via', type: 'text' })
|
|
802
|
+
routedVia!: StaffSupportRoutedVia
|
|
803
|
+
|
|
804
|
+
@Property({ name: 'customer_request_snapshot', type: 'jsonb' })
|
|
805
|
+
customerRequestSnapshot!: { subject: string; body: string }
|
|
806
|
+
|
|
807
|
+
@Property({ name: 'unnotified_at', type: Date, nullable: true })
|
|
808
|
+
unnotifiedAt?: Date | null
|
|
809
|
+
|
|
810
|
+
@Property({ name: 'portal_status_published', type: 'text', nullable: true })
|
|
811
|
+
portalStatusPublished?: StaffSupportPortalStatus | null
|
|
812
|
+
|
|
813
|
+
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
814
|
+
createdAt: Date = new Date()
|
|
815
|
+
|
|
816
|
+
@Property({ name: 'updated_at', type: Date, onUpdate: () => new Date() })
|
|
817
|
+
updatedAt: Date = new Date()
|
|
818
|
+
|
|
819
|
+
@Property({ name: 'deleted_at', type: Date, nullable: true })
|
|
820
|
+
deletedAt?: Date | null
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
@Entity({ tableName: 'staff_support_routing_rules' })
|
|
824
|
+
@Index({ name: 'staff_support_routing_rules_tenant_org_idx', properties: ['tenantId', 'organizationId'] })
|
|
825
|
+
@Index({
|
|
826
|
+
name: 'staff_support_routing_rules_category_unique_idx',
|
|
827
|
+
expression:
|
|
828
|
+
'create unique index "staff_support_routing_rules_category_unique_idx" on "staff_support_routing_rules" ("tenant_id", "organization_id", coalesce("category_value", \'\')) where "deleted_at" is null',
|
|
829
|
+
})
|
|
830
|
+
export class StaffSupportRoutingRule {
|
|
831
|
+
[OptionalProps]?: 'isActive' | 'createdAt' | 'updatedAt'
|
|
832
|
+
|
|
833
|
+
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
834
|
+
id!: string
|
|
835
|
+
|
|
836
|
+
@Property({ name: 'tenant_id', type: 'uuid' })
|
|
837
|
+
tenantId!: string
|
|
838
|
+
|
|
839
|
+
@Property({ name: 'organization_id', type: 'uuid' })
|
|
840
|
+
organizationId!: string
|
|
841
|
+
|
|
842
|
+
@Property({ name: 'category_value', type: 'text', nullable: true })
|
|
843
|
+
categoryValue?: string | null
|
|
844
|
+
|
|
845
|
+
@Property({ name: 'time_project_id', type: 'uuid' })
|
|
846
|
+
timeProjectId!: string
|
|
847
|
+
|
|
848
|
+
@Property({ name: 'is_active', type: 'boolean', default: true })
|
|
849
|
+
isActive: boolean = true
|
|
850
|
+
|
|
732
851
|
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
733
852
|
createdAt: Date = new Date()
|
|
734
853
|
|
|
@@ -743,7 +862,7 @@ export class StaffTimeTask {
|
|
|
743
862
|
@Index({ name: 'staff_time_task_comments_tenant_org_idx', properties: ['tenantId', 'organizationId'] })
|
|
744
863
|
@Index({ name: 'staff_time_task_comments_task_idx', properties: ['organizationId', 'taskId', 'createdAt'] })
|
|
745
864
|
export class StaffTimeTaskComment {
|
|
746
|
-
[OptionalProps]?: 'createdAt' | 'updatedAt'
|
|
865
|
+
[OptionalProps]?: 'visibility' | 'authorKind' | 'createdAt' | 'updatedAt'
|
|
747
866
|
|
|
748
867
|
@PrimaryKey({ type: 'uuid', defaultRaw: 'gen_random_uuid()' })
|
|
749
868
|
id!: string
|
|
@@ -763,6 +882,18 @@ export class StaffTimeTaskComment {
|
|
|
763
882
|
@Property({ name: 'author_user_id', type: 'uuid', nullable: true })
|
|
764
883
|
authorUserId?: string | null
|
|
765
884
|
|
|
885
|
+
@Property({ type: 'text', default: 'internal' })
|
|
886
|
+
visibility: StaffTimeTaskCommentVisibility = 'internal'
|
|
887
|
+
|
|
888
|
+
@Property({ name: 'author_kind', type: 'text', default: 'staff' })
|
|
889
|
+
authorKind: StaffTimeTaskCommentAuthorKind = 'staff'
|
|
890
|
+
|
|
891
|
+
@Property({ name: 'author_customer_user_id', type: 'uuid', nullable: true })
|
|
892
|
+
authorCustomerUserId?: string | null
|
|
893
|
+
|
|
894
|
+
@Property({ name: 'author_display_snapshot', type: 'jsonb', nullable: true })
|
|
895
|
+
authorDisplaySnapshot?: { displayName: string } | null
|
|
896
|
+
|
|
766
897
|
@Property({ name: 'created_at', type: Date, onCreate: () => new Date() })
|
|
767
898
|
createdAt: Date = new Date()
|
|
768
899
|
|
|
@@ -8,7 +8,7 @@ import type { EntityExtension } from '@open-mercato/shared/modules/entities'
|
|
|
8
8
|
* `staff_time_projects.customer_id` are plain uuid columns; the declarations below are
|
|
9
9
|
* the traversal contract over them and nothing more. They contain **string ids only** —
|
|
10
10
|
* no import of a customers or sales symbol — so they add no load-time dependency and
|
|
11
|
-
* staff's `requires
|
|
11
|
+
* staff's `requires` in `index.ts` never gains `customers` or `sales`. That matters:
|
|
12
12
|
* staff is slated for extraction into a standalone package, and a link that pulled in
|
|
13
13
|
* `@open-mercato/core/modules/customers` would break the extraction.
|
|
14
14
|
*
|
|
@@ -62,6 +62,14 @@ const entityExtensions: EntityExtension[] = [
|
|
|
62
62
|
cardinality: 'one-to-many',
|
|
63
63
|
description: 'Time projects owned by a customer record (D-9: the customers supertype)',
|
|
64
64
|
},
|
|
65
|
+
{
|
|
66
|
+
base: 'customers:customer_entity',
|
|
67
|
+
extension: 'staff:staff_time_task',
|
|
68
|
+
join: { baseKey: 'id', extensionKey: 'customer_id' },
|
|
69
|
+
table: 'staff_time_tasks',
|
|
70
|
+
cardinality: 'one-to-many',
|
|
71
|
+
description: 'Tasks filed for a customer record, such as customer portal support tickets',
|
|
72
|
+
},
|
|
65
73
|
]
|
|
66
74
|
|
|
67
75
|
export const extensions = entityExtensions
|
|
@@ -476,6 +476,7 @@ export const staffTimeProjectUpdateSchema = z.object({
|
|
|
476
476
|
budgetKind: timeProjectBudgetKindSchema.optional(),
|
|
477
477
|
budgetValue: numericAmountSchema.optional().nullable(),
|
|
478
478
|
budgetWarnAtPercent: z.number().int().min(1).max(100).optional(),
|
|
479
|
+
defaultAssigneeStaffMemberId: z.string().uuid().optional().nullable(),
|
|
479
480
|
})
|
|
480
481
|
|
|
481
482
|
export const staffTimeProjectMemberAssignSchema = z.object({
|
|
@@ -486,6 +487,7 @@ export const staffTimeProjectMemberAssignSchema = z.object({
|
|
|
486
487
|
status: timeProjectMemberStatusSchema.optional().default('active'),
|
|
487
488
|
assignedStartDate: z.coerce.date(),
|
|
488
489
|
assignedEndDate: z.coerce.date().optional().nullable(),
|
|
490
|
+
isAssigner: z.boolean().optional(),
|
|
489
491
|
})
|
|
490
492
|
|
|
491
493
|
export const staffTimeProjectMemberUpdateSchema = z.object({
|
|
@@ -493,6 +495,7 @@ export const staffTimeProjectMemberUpdateSchema = z.object({
|
|
|
493
495
|
role: z.string().max(100).optional().nullable(),
|
|
494
496
|
status: timeProjectMemberStatusSchema.optional(),
|
|
495
497
|
assignedEndDate: z.coerce.date().optional().nullable(),
|
|
498
|
+
isAssigner: z.boolean().optional(),
|
|
496
499
|
})
|
|
497
500
|
|
|
498
501
|
export const staffMyProjectVisibilityUpdateSchema = z.object({
|
|
@@ -596,13 +599,24 @@ export const staffTimeTaskCommentCreateSchema = z.object({
|
|
|
596
599
|
taskId: z.string().uuid(),
|
|
597
600
|
body: z.string().trim().min(1).max(5000),
|
|
598
601
|
authorUserId: z.string().uuid().optional().nullable(),
|
|
602
|
+
visibility: z.enum(['internal', 'customer']).optional(),
|
|
599
603
|
})
|
|
600
604
|
|
|
601
605
|
export const staffTimeTaskCommentUpdateSchema = z.object({
|
|
602
606
|
...scopedUpdateFields,
|
|
603
607
|
body: z.string().trim().min(1).max(5000),
|
|
608
|
+
visibility: z.enum(['internal', 'customer']).optional(),
|
|
604
609
|
})
|
|
605
610
|
|
|
611
|
+
export const staffTimeTaskCommentUpdateRequestSchema = staffTimeTaskCommentUpdateSchema
|
|
612
|
+
.extend({
|
|
613
|
+
body: z.string().trim().min(1).max(5000).optional(),
|
|
614
|
+
})
|
|
615
|
+
.refine((value) => value.body !== undefined || value.visibility !== undefined, {
|
|
616
|
+
message: 'body or visibility is required',
|
|
617
|
+
path: ['body'],
|
|
618
|
+
})
|
|
619
|
+
|
|
606
620
|
export const staffTimeTagCreateSchema = z.object({
|
|
607
621
|
...scopedCreateFields,
|
|
608
622
|
slug: timeSlugSchema,
|
|
@@ -721,6 +735,7 @@ export type StaffTimeTaskUpdateInput = z.infer<typeof staffTimeTaskUpdateSchema>
|
|
|
721
735
|
export type StaffTimeTaskStatusChangeInput = z.infer<typeof staffTimeTaskStatusChangeSchema>
|
|
722
736
|
export type StaffTimeTaskCommentCreateInput = z.infer<typeof staffTimeTaskCommentCreateSchema>
|
|
723
737
|
export type StaffTimeTaskCommentUpdateInput = z.infer<typeof staffTimeTaskCommentUpdateSchema>
|
|
738
|
+
export type StaffTimeTaskCommentUpdateRequestInput = z.infer<typeof staffTimeTaskCommentUpdateRequestSchema>
|
|
724
739
|
export type StaffTimeTagCreateInput = z.infer<typeof staffTimeTagCreateSchema>
|
|
725
740
|
export type StaffTimeTaskTagAssignmentInput = z.infer<typeof staffTimeTaskTagAssignmentSchema>
|
|
726
741
|
export type StaffTimeEntryTagAssignmentInput = z.infer<typeof staffTimeEntryTagAssignmentSchema>
|
|
@@ -731,3 +746,24 @@ export type StaffTimeReportCloseInput = z.infer<typeof staffTimeReportCloseSchem
|
|
|
731
746
|
export type StaffTimeReportUnlockInput = z.infer<typeof staffTimeReportUnlockSchema>
|
|
732
747
|
export type StaffTimeProjectChangeCurrencyInput = z.infer<typeof staffTimeProjectChangeCurrencySchema>
|
|
733
748
|
export type StaffTimeTrackingSettingsInput = z.infer<typeof staffTimeTrackingSettingsSchema>
|
|
749
|
+
|
|
750
|
+
export const staffSupportRoutingRuleCreateSchema = z.object({
|
|
751
|
+
...scopedCreateFields,
|
|
752
|
+
categoryValue: z.string().trim().min(1).max(150).optional().nullable(),
|
|
753
|
+
timeProjectId: z.string().uuid(),
|
|
754
|
+
isActive: z.boolean().optional().default(true),
|
|
755
|
+
})
|
|
756
|
+
|
|
757
|
+
export const staffSupportRoutingRuleUpdateSchema = z.object({
|
|
758
|
+
...scopedUpdateFields,
|
|
759
|
+
timeProjectId: z.string().uuid().optional(),
|
|
760
|
+
isActive: z.boolean().optional(),
|
|
761
|
+
})
|
|
762
|
+
|
|
763
|
+
export const staffSupportFallbackProjectCreateSchema = z.object({
|
|
764
|
+
...scopedCreateFields,
|
|
765
|
+
})
|
|
766
|
+
|
|
767
|
+
export type StaffSupportRoutingRuleCreateInput = z.infer<typeof staffSupportRoutingRuleCreateSchema>
|
|
768
|
+
export type StaffSupportRoutingRuleUpdateInput = z.infer<typeof staffSupportRoutingRuleUpdateSchema>
|
|
769
|
+
export type StaffSupportFallbackProjectCreateInput = z.infer<typeof staffSupportFallbackProjectCreateSchema>
|
|
@@ -9,6 +9,12 @@ export const defaultEncryptionMaps: ModuleEncryptionMap[] = [
|
|
|
9
9
|
{ field: 'unavailability_reason_value' },
|
|
10
10
|
],
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
entityId: 'staff:staff_support_ticket',
|
|
14
|
+
fields: [
|
|
15
|
+
{ field: 'customer_request_snapshot' },
|
|
16
|
+
],
|
|
17
|
+
},
|
|
12
18
|
]
|
|
13
19
|
|
|
14
20
|
export default defaultEncryptionMaps
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Payload contracts for the `staff.timesheets.*` event
|
|
2
|
+
* Payload contracts for the `staff.timesheets.*` and `staff.support_ticket.*` event families.
|
|
3
3
|
*
|
|
4
4
|
* **Why this file exists.** Outbound webhooks in this platform are not registered
|
|
5
5
|
* per event: `packages/webhooks` subscribes once with `event: '*'`
|
|
@@ -109,6 +109,18 @@ const taskStatusChanged = scope
|
|
|
109
109
|
})
|
|
110
110
|
.passthrough()
|
|
111
111
|
|
|
112
|
+
/** Ids only: the event is `clientBroadcast: true`, so no names, no customer and no text. */
|
|
113
|
+
const taskAssigneeChanged = scope
|
|
114
|
+
.extend({
|
|
115
|
+
id: z.string(),
|
|
116
|
+
timeProjectId: z.string(),
|
|
117
|
+
previousAssigneeStaffMemberId: z.string().nullable(),
|
|
118
|
+
assigneeStaffMemberId: z.string().nullable(),
|
|
119
|
+
changeKind: z.enum(['default', 'claim', 'release', 'manual']),
|
|
120
|
+
actorUserId: z.string().nullable().optional(),
|
|
121
|
+
})
|
|
122
|
+
.passthrough()
|
|
123
|
+
|
|
112
124
|
/**
|
|
113
125
|
* No `customerId`: the event is `clientBroadcast: true` and the DOM Event Bridge
|
|
114
126
|
* applies no feature check, so the one field linking a report to a named client is
|
|
@@ -241,6 +253,7 @@ export const staffTimeTrackingEventPayloadSchemas = {
|
|
|
241
253
|
'staff.timesheets.time_task.updated': crudPayload,
|
|
242
254
|
'staff.timesheets.time_task.deleted': crudPayload,
|
|
243
255
|
'staff.timesheets.time_task.status_changed': taskStatusChanged,
|
|
256
|
+
'staff.timesheets.time_task.assignee_changed': taskAssigneeChanged,
|
|
244
257
|
'staff.timesheets.time_task_status.created': crudPayload,
|
|
245
258
|
'staff.timesheets.time_task_status.updated': crudPayload,
|
|
246
259
|
'staff.timesheets.time_task_status.deleted': crudPayload,
|
|
@@ -266,3 +279,76 @@ export type StaffTimeTrackingEventId = keyof typeof staffTimeTrackingEventPayloa
|
|
|
266
279
|
export type StaffTimeTrackingEventPayload<TEventId extends StaffTimeTrackingEventId> = z.infer<
|
|
267
280
|
typeof staffTimeTrackingEventPayloadSchemas[TEventId]
|
|
268
281
|
>
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Names the customer and the ticket reference, so the event stays server-side
|
|
285
|
+
* (no `clientBroadcast`); webhooks and the notification subscriber read it.
|
|
286
|
+
*/
|
|
287
|
+
const supportTicketCreated = scope
|
|
288
|
+
.extend({
|
|
289
|
+
id: z.string(),
|
|
290
|
+
taskId: z.string(),
|
|
291
|
+
projectId: z.string(),
|
|
292
|
+
customerId: z.string(),
|
|
293
|
+
supportReference: z.string(),
|
|
294
|
+
categoryValue: z.string(),
|
|
295
|
+
})
|
|
296
|
+
.passthrough()
|
|
297
|
+
|
|
298
|
+
const supportTicketCustomerReplied = scope
|
|
299
|
+
.extend({
|
|
300
|
+
id: z.string(),
|
|
301
|
+
taskId: z.string(),
|
|
302
|
+
projectId: z.string(),
|
|
303
|
+
commentId: z.string(),
|
|
304
|
+
supportReference: z.string(),
|
|
305
|
+
})
|
|
306
|
+
.passthrough()
|
|
307
|
+
|
|
308
|
+
/** Ids only: the event is `clientBroadcast: true`, so no customer, no reference and no text. */
|
|
309
|
+
const supportTicketActivityRecorded = scope
|
|
310
|
+
.extend({
|
|
311
|
+
id: z.string(),
|
|
312
|
+
taskId: z.string(),
|
|
313
|
+
projectId: z.string(),
|
|
314
|
+
kind: z.enum(['created', 'customer_replied', 'portal_status', 'attachment_added', 'attachment_removed']),
|
|
315
|
+
/** The changed attachment for `attachment_added` / `attachment_removed`, so distinct changes stay distinct for the 500 ms duplicate filter. */
|
|
316
|
+
attachmentId: z.string().optional(),
|
|
317
|
+
})
|
|
318
|
+
.passthrough()
|
|
319
|
+
|
|
320
|
+
const supportTicketPortalUpdated = scope
|
|
321
|
+
.extend({
|
|
322
|
+
id: z.string(),
|
|
323
|
+
ticketId: z.string(),
|
|
324
|
+
supportReference: z.string(),
|
|
325
|
+
portalStatus: z.enum(['received', 'in_progress', 'resolved']),
|
|
326
|
+
kind: z.enum(['status', 'reply']),
|
|
327
|
+
/** The change announced: the task version for `status`, the comment id for `reply`. Keeps distinct changes distinct for the portal bridge's 500 ms duplicate filter. */
|
|
328
|
+
version: z.string().optional(),
|
|
329
|
+
/**
|
|
330
|
+
* The portal SSE stream narrows a broadcast to these customer-user ids. The
|
|
331
|
+
* emitter never publishes this event with an empty list, so a ticket update can
|
|
332
|
+
* only ever reach the portal users of the ticket's own customer.
|
|
333
|
+
*/
|
|
334
|
+
recipientUserIds: z.array(z.string()).min(1),
|
|
335
|
+
})
|
|
336
|
+
.passthrough()
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Every declared `staff.support_ticket.*` event id and the payload a webhook endpoint
|
|
340
|
+
* subscribed to it receives. Same rules as the time-tracking map above: `tenantId` is
|
|
341
|
+
* required and every schema is `passthrough()`.
|
|
342
|
+
*/
|
|
343
|
+
export const staffSupportTicketEventPayloadSchemas = {
|
|
344
|
+
'staff.support_ticket.created': supportTicketCreated,
|
|
345
|
+
'staff.support_ticket.customer_replied': supportTicketCustomerReplied,
|
|
346
|
+
'staff.support_ticket.activity_recorded': supportTicketActivityRecorded,
|
|
347
|
+
'staff.support_ticket.portal_updated': supportTicketPortalUpdated,
|
|
348
|
+
} as const
|
|
349
|
+
|
|
350
|
+
export type StaffSupportTicketEventId = keyof typeof staffSupportTicketEventPayloadSchemas
|
|
351
|
+
|
|
352
|
+
export type StaffSupportTicketEventPayload<TEventId extends StaffSupportTicketEventId> = z.infer<
|
|
353
|
+
typeof staffSupportTicketEventPayloadSchemas[TEventId]
|
|
354
|
+
>
|