@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
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
import { buildEncryptionMapBackfillSql } from '@open-mercato/shared/lib/encryption/migration-backfill';
|
|
3
|
+
|
|
4
|
+
export class Migration20261009180543_staff extends Migration {
|
|
5
|
+
|
|
6
|
+
override name = 'Migration20261009180543';
|
|
7
|
+
|
|
8
|
+
override up(): void | Promise<void> {
|
|
9
|
+
this.addSql(`create table "staff_support_routing_rules" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "category_value" text null, "time_project_id" uuid not null, "is_active" boolean not null default true, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
10
|
+
this.addSql(`create index "staff_support_routing_rules_tenant_org_idx" on "staff_support_routing_rules" ("tenant_id", "organization_id");`);
|
|
11
|
+
this.addSql(`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;`);
|
|
12
|
+
|
|
13
|
+
this.addSql(`create table "staff_support_tickets" ("id" uuid not null default gen_random_uuid(), "tenant_id" uuid not null, "organization_id" uuid not null, "task_id" uuid not null, "customer_snapshot" jsonb null, "reported_by_customer_user_id" uuid null, "support_reference" text not null, "support_sequence_number" int not null, "category_value" text not null, "category_snapshot" jsonb not null, "routed_via" text not null, "customer_request_snapshot" jsonb not null, "unnotified_at" timestamptz null, "portal_status_published" text null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, primary key ("id"));`);
|
|
14
|
+
this.addSql(`create unique index "staff_support_tickets_reference_unique_idx" on "staff_support_tickets" ("tenant_id", "organization_id", "support_reference") where "deleted_at" is null;`);
|
|
15
|
+
this.addSql(`create index "staff_support_tickets_sequence_idx" on "staff_support_tickets" ("tenant_id", "organization_id", "support_sequence_number");`);
|
|
16
|
+
this.addSql(`create unique index "staff_support_tickets_task_unique_idx" on "staff_support_tickets" ("tenant_id", "organization_id", "task_id") where "deleted_at" is null;`);
|
|
17
|
+
this.addSql(`create index "staff_support_tickets_tenant_org_idx" on "staff_support_tickets" ("tenant_id", "organization_id");`);
|
|
18
|
+
|
|
19
|
+
this.addSql(`alter table "staff_time_projects" add "default_assignee_staff_member_id" uuid null;`);
|
|
20
|
+
|
|
21
|
+
this.addSql(`alter table "staff_time_project_members" add "is_assigner" boolean not null default false;`);
|
|
22
|
+
this.addSql(`create index "staff_time_project_members_assigner_idx" on "staff_time_project_members" ("tenant_id", "organization_id", "time_project_id") where "is_assigner" = true and "status" = 'active' and "deleted_at" is null;`);
|
|
23
|
+
|
|
24
|
+
this.addSql(`alter table "staff_time_tasks" add "source" text not null default 'internal', add "customer_id" uuid null;`);
|
|
25
|
+
this.addSql(`create index "staff_time_tasks_portal_customer_idx" on "staff_time_tasks" ("tenant_id", "organization_id", "customer_id", "updated_at") where "source" = 'portal' and "deleted_at" is null;`);
|
|
26
|
+
|
|
27
|
+
this.addSql(`alter table "staff_time_task_comments" add "visibility" text not null default 'internal', add "author_kind" text not null default 'staff', add "author_customer_user_id" uuid null, add "author_display_snapshot" jsonb null;`);
|
|
28
|
+
|
|
29
|
+
this.addSql(buildEncryptionMapBackfillSql({
|
|
30
|
+
entityId: 'staff:staff_support_ticket',
|
|
31
|
+
fields: [{ field: 'customer_request_snapshot' }],
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
override down(): void | Promise<void> {
|
|
36
|
+
this.addSql(`drop table if exists "staff_support_tickets";`);
|
|
37
|
+
this.addSql(`drop table if exists "staff_support_routing_rules";`);
|
|
38
|
+
|
|
39
|
+
this.addSql(`drop index "staff_time_project_members_assigner_idx";`);
|
|
40
|
+
this.addSql(`alter table "staff_time_project_members" drop column "is_assigner";`);
|
|
41
|
+
|
|
42
|
+
this.addSql(`alter table "staff_time_projects" drop column "default_assignee_staff_member_id";`);
|
|
43
|
+
|
|
44
|
+
this.addSql(`alter table "staff_time_task_comments" drop column "visibility", drop column "author_kind", drop column "author_customer_user_id", drop column "author_display_snapshot";`);
|
|
45
|
+
|
|
46
|
+
this.addSql(`drop index "staff_time_tasks_portal_customer_idx";`);
|
|
47
|
+
this.addSql(`alter table "staff_time_tasks" drop column "source", drop column "customer_id";`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
}
|
|
@@ -235,6 +235,98 @@ export const notificationTypes: NotificationTypeDefinition[] = [
|
|
|
235
235
|
linkHref: '/backend/staff/time-tracking/timesheet',
|
|
236
236
|
expiresAfterHours: 168, // 7 days
|
|
237
237
|
},
|
|
238
|
+
{
|
|
239
|
+
// Customer support tickets: raised for every portal ticket. The audience is the
|
|
240
|
+
// assignee (when the project default applied) plus the project's active
|
|
241
|
+
// assigners, falling back through owner and organization project managers.
|
|
242
|
+
type: 'staff.support_ticket.created',
|
|
243
|
+
channels: ['in_app', 'email'],
|
|
244
|
+
module: 'staff',
|
|
245
|
+
titleKey: 'staff.notifications.supportTicket.created.title',
|
|
246
|
+
bodyKey: 'staff.notifications.supportTicket.created.body',
|
|
247
|
+
icon: 'life-buoy',
|
|
248
|
+
severity: 'info',
|
|
249
|
+
actions: [
|
|
250
|
+
{
|
|
251
|
+
id: 'open-ticket',
|
|
252
|
+
labelKey: 'staff.notifications.supportTicket.actions.open',
|
|
253
|
+
variant: 'default',
|
|
254
|
+
icon: 'external-link',
|
|
255
|
+
href: '/backend/staff/time-tracking/support?task={sourceEntityId}',
|
|
256
|
+
},
|
|
257
|
+
],
|
|
258
|
+
primaryActionId: 'open-ticket',
|
|
259
|
+
linkHref: '/backend/staff/time-tracking/support?task={sourceEntityId}',
|
|
260
|
+
expiresAfterHours: 336,
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
type: 'staff.support_ticket.customer_replied',
|
|
264
|
+
channels: ['in_app', 'email'],
|
|
265
|
+
module: 'staff',
|
|
266
|
+
titleKey: 'staff.notifications.supportTicket.customerReplied.title',
|
|
267
|
+
bodyKey: 'staff.notifications.supportTicket.customerReplied.body',
|
|
268
|
+
icon: 'message-square',
|
|
269
|
+
severity: 'info',
|
|
270
|
+
actions: [
|
|
271
|
+
{
|
|
272
|
+
id: 'open-ticket',
|
|
273
|
+
labelKey: 'staff.notifications.supportTicket.actions.open',
|
|
274
|
+
variant: 'default',
|
|
275
|
+
icon: 'external-link',
|
|
276
|
+
href: '/backend/staff/time-tracking/support?task={sourceEntityId}',
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
primaryActionId: 'open-ticket',
|
|
280
|
+
linkHref: '/backend/staff/time-tracking/support?task={sourceEntityId}',
|
|
281
|
+
expiresAfterHours: 336,
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
// A task in the project became unassigned (released or cleared): tells the
|
|
285
|
+
// project's assigners there is claimable work.
|
|
286
|
+
type: 'staff.timesheets.time_task.released',
|
|
287
|
+
channels: ['in_app'],
|
|
288
|
+
module: 'staff',
|
|
289
|
+
titleKey: 'staff.notifications.timeTask.released.title',
|
|
290
|
+
bodyKey: 'staff.notifications.timeTask.released.body',
|
|
291
|
+
icon: 'hand',
|
|
292
|
+
severity: 'info',
|
|
293
|
+
actions: [
|
|
294
|
+
{
|
|
295
|
+
id: 'open-task',
|
|
296
|
+
labelKey: 'staff.notifications.timeTask.actions.open',
|
|
297
|
+
variant: 'default',
|
|
298
|
+
icon: 'external-link',
|
|
299
|
+
href: '/backend/staff/time-tracking/board?task={sourceEntityId}',
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
primaryActionId: 'open-task',
|
|
303
|
+
linkHref: '/backend/staff/time-tracking/board?task={sourceEntityId}',
|
|
304
|
+
expiresAfterHours: 168,
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
// Someone else assigned the recipient to a task through the task editor. Not sent
|
|
308
|
+
// for claims (self-assignment) or for the portal default assignee, who hears
|
|
309
|
+
// about the intake once through `staff.support_ticket.created`.
|
|
310
|
+
type: 'staff.timesheets.time_task.assigned',
|
|
311
|
+
channels: ['in_app'],
|
|
312
|
+
module: 'staff',
|
|
313
|
+
titleKey: 'staff.notifications.timeTask.assigned.title',
|
|
314
|
+
bodyKey: 'staff.notifications.timeTask.assigned.body',
|
|
315
|
+
icon: 'user-check',
|
|
316
|
+
severity: 'info',
|
|
317
|
+
actions: [
|
|
318
|
+
{
|
|
319
|
+
id: 'open-task',
|
|
320
|
+
labelKey: 'staff.notifications.timeTask.actions.open',
|
|
321
|
+
variant: 'default',
|
|
322
|
+
icon: 'external-link',
|
|
323
|
+
href: '/backend/staff/time-tracking/board?task={sourceEntityId}',
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
primaryActionId: 'open-task',
|
|
327
|
+
linkHref: '/backend/staff/time-tracking/board?task={sourceEntityId}',
|
|
328
|
+
expiresAfterHours: 168,
|
|
329
|
+
},
|
|
238
330
|
]
|
|
239
331
|
|
|
240
332
|
export default notificationTypes
|
|
@@ -2,6 +2,8 @@ import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
|
|
|
2
2
|
import { appendWidgetsToRoles } from '@open-mercato/core/modules/dashboards/lib/role-widgets'
|
|
3
3
|
import { seedStaffAddressTypes, seedStaffTeamExamples } from './lib/seeds'
|
|
4
4
|
import { seedStaffTimeTrackingExamples } from './lib/timeTrackingSeeds'
|
|
5
|
+
import { resolveContainerProjectCodeGenerator, seedSupportDefaults } from './lib/support/seedDefaults'
|
|
6
|
+
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
5
7
|
|
|
6
8
|
const TIMESHEETS_DASHBOARD_WIDGET_IDS = [
|
|
7
9
|
'staff.timesheets.timeReporting',
|
|
@@ -12,6 +14,8 @@ export const setup: ModuleSetupConfig = {
|
|
|
12
14
|
seedDefaults: async (ctx) => {
|
|
13
15
|
const scope = { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
|
|
14
16
|
await seedStaffAddressTypes(ctx.em, scope)
|
|
17
|
+
const { translate } = await resolveTranslations()
|
|
18
|
+
await seedSupportDefaults(ctx.em, scope, { translate, generateCode: resolveContainerProjectCodeGenerator(ctx.container) })
|
|
15
19
|
await appendWidgetsToRoles(ctx.em, {
|
|
16
20
|
tenantId: ctx.tenantId,
|
|
17
21
|
organizationId: ctx.organizationId,
|
|
@@ -56,8 +60,8 @@ export const setup: ModuleSetupConfig = {
|
|
|
56
60
|
* `portal_admin` holds `portal.*` and needs no entry.
|
|
57
61
|
*/
|
|
58
62
|
defaultCustomerRoleFeatures: {
|
|
59
|
-
buyer: ['portal.time_reports.view'],
|
|
60
|
-
viewer: ['portal.time_reports.view'],
|
|
63
|
+
buyer: ['portal.time_reports.view', 'portal.support_tickets.view', 'portal.support_tickets.manage'],
|
|
64
|
+
viewer: ['portal.time_reports.view', 'portal.support_tickets.view'],
|
|
61
65
|
},
|
|
62
66
|
}
|
|
63
67
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
4
|
+
import { publishTicketReply, readEventScope } from '../lib/support/portalBroadcast'
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-comment-created' })
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ephemeral on purpose: `portal_updated` is portal-only, and the event bus does not
|
|
10
|
+
* relay portal-only events across processes (open issue #2973). Run inline in the web
|
|
11
|
+
* process that executed the command, where the portal SSE stream lives. Make this
|
|
12
|
+
* persistent again once #2973 lands.
|
|
13
|
+
*/
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task_comment.created',
|
|
16
|
+
persistent: false,
|
|
17
|
+
id: 'staff:support-portal-comment-created',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
21
|
+
|
|
22
|
+
type Payload = Record<string, unknown>
|
|
23
|
+
|
|
24
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
if (payload.portalVisible !== true) return
|
|
27
|
+
const scope = readEventScope(payload)
|
|
28
|
+
const commentId = typeof payload.id === 'string' ? payload.id : null
|
|
29
|
+
if (!scope || !commentId) return
|
|
30
|
+
await publishTicketReply((ctx.resolve('em') as EntityManager).fork(), commentId, scope)
|
|
31
|
+
} catch (err) {
|
|
32
|
+
logger.error('staff:support-portal-comment-created failed', { err, id: payload?.id ?? null })
|
|
33
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.support_portal_comment_created_failed' })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
4
|
+
import { publishTicketReply, readEventScope } from '../lib/support/portalBroadcast'
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-comment-deleted' })
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ephemeral on purpose: `portal_updated` is portal-only, and the event bus does not
|
|
10
|
+
* relay portal-only events across processes (open issue #2973). Run inline in the web
|
|
11
|
+
* process that executed the command, where the portal SSE stream lives. Make this
|
|
12
|
+
* persistent again once #2973 lands.
|
|
13
|
+
*/
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task_comment.deleted',
|
|
16
|
+
persistent: false,
|
|
17
|
+
id: 'staff:support-portal-comment-deleted',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
21
|
+
|
|
22
|
+
type Payload = Record<string, unknown>
|
|
23
|
+
|
|
24
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
if (payload.portalVisible !== true) return
|
|
27
|
+
const scope = readEventScope(payload)
|
|
28
|
+
const commentId = typeof payload.id === 'string' ? payload.id : null
|
|
29
|
+
if (!scope || !commentId) return
|
|
30
|
+
await publishTicketReply((ctx.resolve('em') as EntityManager).fork(), commentId, scope)
|
|
31
|
+
} catch (err) {
|
|
32
|
+
logger.error('staff:support-portal-comment-deleted failed', { err, id: payload?.id ?? null })
|
|
33
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.support_portal_comment_deleted_failed' })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
4
|
+
import { publishTicketReply, readEventScope } from '../lib/support/portalBroadcast'
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-comment-updated' })
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ephemeral on purpose: `portal_updated` is portal-only, and the event bus does not
|
|
10
|
+
* relay portal-only events across processes (open issue #2973). Run inline in the web
|
|
11
|
+
* process that executed the command, where the portal SSE stream lives. Make this
|
|
12
|
+
* persistent again once #2973 lands.
|
|
13
|
+
*/
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task_comment.updated',
|
|
16
|
+
persistent: false,
|
|
17
|
+
id: 'staff:support-portal-comment-updated',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
21
|
+
|
|
22
|
+
type Payload = Record<string, unknown>
|
|
23
|
+
|
|
24
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
if (payload.portalVisible !== true) return
|
|
27
|
+
const scope = readEventScope(payload)
|
|
28
|
+
const commentId = typeof payload.id === 'string' ? payload.id : null
|
|
29
|
+
if (!scope || !commentId) return
|
|
30
|
+
await publishTicketReply((ctx.resolve('em') as EntityManager).fork(), commentId, scope)
|
|
31
|
+
} catch (err) {
|
|
32
|
+
logger.error('staff:support-portal-comment-updated failed', { err, id: payload?.id ?? null })
|
|
33
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.support_portal_comment_updated_failed' })
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { fanOutStatusColumn, readEventScope } from '../lib/support/portalBroadcast'
|
|
4
|
+
|
|
5
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-status-column-updated' })
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Persistent, unlike the other support-portal subscribers: re-deriving every portal
|
|
9
|
+
* ticket in a column is the one potentially expensive fan-out, so it runs on the
|
|
10
|
+
* queue (retried on failure; `publishTaskPortalStatus` is compare-and-publish, so a
|
|
11
|
+
* retry is idempotent) instead of inside the admin's request. Column flag edits are
|
|
12
|
+
* rare, and until #2973 lands a `portal_updated` emitted from the worker may not
|
|
13
|
+
* reach an open portal page live; the portal derives status on read, so the page is
|
|
14
|
+
* correct on its next load.
|
|
15
|
+
*/
|
|
16
|
+
export const metadata = {
|
|
17
|
+
event: 'staff.timesheets.time_task_status.updated',
|
|
18
|
+
persistent: true,
|
|
19
|
+
id: 'staff:support-portal-status-column-updated',
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
23
|
+
|
|
24
|
+
type Payload = Record<string, unknown>
|
|
25
|
+
|
|
26
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
27
|
+
try {
|
|
28
|
+
const scope = readEventScope(payload)
|
|
29
|
+
const statusId = typeof payload.id === 'string' ? payload.id : null
|
|
30
|
+
if (!scope || !statusId) return
|
|
31
|
+
await fanOutStatusColumn((ctx.resolve('em') as EntityManager).fork(), statusId, scope)
|
|
32
|
+
} catch (err) {
|
|
33
|
+
logger.error('staff:support-portal-status-column-updated failed', { err, id: payload?.id ?? null })
|
|
34
|
+
throw err
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
4
|
+
import { publishTaskPortalStatus, readEventScope } from '../lib/support/portalBroadcast'
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-task-status-changed' })
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ephemeral on purpose: `portal_updated` is portal-only, and the event bus does not
|
|
10
|
+
* relay portal-only events across processes (open issue #2973). Run inline in the web
|
|
11
|
+
* process that executed the command, where the portal SSE stream lives. Make this
|
|
12
|
+
* persistent again once #2973 lands.
|
|
13
|
+
*/
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task.status_changed',
|
|
16
|
+
persistent: false,
|
|
17
|
+
id: 'staff:support-portal-task-status-changed',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
21
|
+
|
|
22
|
+
type Payload = Record<string, unknown>
|
|
23
|
+
|
|
24
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
const scope = readEventScope(payload)
|
|
27
|
+
const taskId = typeof payload.id === 'string' ? payload.id : null
|
|
28
|
+
if (!scope || !taskId) return
|
|
29
|
+
await publishTaskPortalStatus((ctx.resolve('em') as EntityManager).fork(), taskId, scope, { always: true })
|
|
30
|
+
} catch (err) {
|
|
31
|
+
logger.error('staff:support-portal-task-status-changed failed', { err, id: payload?.id ?? null })
|
|
32
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.support_portal_task_status_changed_failed' })
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
4
|
+
import { publishTaskPortalStatus, readEventScope } from '../lib/support/portalBroadcast'
|
|
5
|
+
|
|
6
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-portal-task-updated' })
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Ephemeral on purpose: `portal_updated` is portal-only, and the event bus does not
|
|
10
|
+
* relay portal-only events across processes (open issue #2973). Run inline in the web
|
|
11
|
+
* process that executed the command, where the portal SSE stream lives. Make this
|
|
12
|
+
* persistent again once #2973 lands.
|
|
13
|
+
*/
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task.updated',
|
|
16
|
+
persistent: false,
|
|
17
|
+
id: 'staff:support-portal-task-updated',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
21
|
+
|
|
22
|
+
type Payload = Record<string, unknown>
|
|
23
|
+
|
|
24
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
25
|
+
try {
|
|
26
|
+
const scope = readEventScope(payload)
|
|
27
|
+
const taskId = typeof payload.id === 'string' ? payload.id : null
|
|
28
|
+
if (!scope || !taskId) return
|
|
29
|
+
await publishTaskPortalStatus((ctx.resolve('em') as EntityManager).fork(), taskId, scope)
|
|
30
|
+
} catch (err) {
|
|
31
|
+
logger.error('staff:support-portal-task-updated failed', { err, id: payload?.id ?? null })
|
|
32
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.support_portal_task_updated_failed' })
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
2
|
+
import { notifySupportTicket } from '../lib/support/notifications'
|
|
3
|
+
|
|
4
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-ticket-created-notification' })
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
event: 'staff.support_ticket.created',
|
|
8
|
+
persistent: true,
|
|
9
|
+
id: 'staff:support-ticket-created-notification',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
13
|
+
|
|
14
|
+
type Payload = Record<string, unknown>
|
|
15
|
+
|
|
16
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
17
|
+
try {
|
|
18
|
+
const taskId = typeof payload.taskId === 'string' ? payload.taskId : null
|
|
19
|
+
const tenantId = typeof payload.tenantId === 'string' ? payload.tenantId : null
|
|
20
|
+
const organizationId = typeof payload.organizationId === 'string' ? payload.organizationId : null
|
|
21
|
+
if (!taskId || !tenantId || !organizationId) return
|
|
22
|
+
await notifySupportTicket(ctx, { taskId, tenantId, organizationId, kind: 'created' })
|
|
23
|
+
} catch (err) {
|
|
24
|
+
logger.error('staff:support-ticket-created-notification failed', { err, id: payload?.id ?? null })
|
|
25
|
+
throw err
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
2
|
+
import { notifySupportTicket } from '../lib/support/notifications'
|
|
3
|
+
|
|
4
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-ticket-customer-replied-notification' })
|
|
5
|
+
|
|
6
|
+
export const metadata = {
|
|
7
|
+
event: 'staff.support_ticket.customer_replied',
|
|
8
|
+
persistent: true,
|
|
9
|
+
id: 'staff:support-ticket-customer-replied-notification',
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
13
|
+
|
|
14
|
+
type Payload = Record<string, unknown>
|
|
15
|
+
|
|
16
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
17
|
+
try {
|
|
18
|
+
const taskId = typeof payload.taskId === 'string' ? payload.taskId : null
|
|
19
|
+
const tenantId = typeof payload.tenantId === 'string' ? payload.tenantId : null
|
|
20
|
+
const organizationId = typeof payload.organizationId === 'string' ? payload.organizationId : null
|
|
21
|
+
if (!taskId || !tenantId || !organizationId) return
|
|
22
|
+
await notifySupportTicket(ctx, { taskId, tenantId, organizationId, kind: 'customer_replied' })
|
|
23
|
+
} catch (err) {
|
|
24
|
+
logger.error('staff:support-ticket-customer-replied-notification failed', { err, id: payload?.id ?? null })
|
|
25
|
+
throw err
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { clearSupportTicketUnnotified } from '../lib/support/notifications'
|
|
4
|
+
|
|
5
|
+
const logger = createLogger('staff').child({ component: 'subscribers/support-ticket-unnotified-clear' })
|
|
6
|
+
|
|
7
|
+
export const metadata = {
|
|
8
|
+
event: 'staff.timesheets.time_task.assignee_changed',
|
|
9
|
+
persistent: true,
|
|
10
|
+
id: 'staff:support-ticket-unnotified-clear',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type ResolverContext = { resolve: <T = unknown>(name: string) => T }
|
|
14
|
+
|
|
15
|
+
type Payload = Record<string, unknown>
|
|
16
|
+
|
|
17
|
+
export default async function handle(payload: Payload, ctx: ResolverContext): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
const taskId = typeof payload.id === 'string' ? payload.id : null
|
|
20
|
+
const tenantId = typeof payload.tenantId === 'string' ? payload.tenantId : null
|
|
21
|
+
const organizationId = typeof payload.organizationId === 'string' ? payload.organizationId : null
|
|
22
|
+
if (!taskId || !tenantId || !organizationId || !payload.assigneeStaffMemberId) return
|
|
23
|
+
const em = (ctx.resolve('em') as EntityManager).fork()
|
|
24
|
+
await clearSupportTicketUnnotified(em, { taskId, tenantId, organizationId })
|
|
25
|
+
} catch (err) {
|
|
26
|
+
logger.error('staff:support-ticket-unnotified-clear failed', { err, id: payload?.id ?? null })
|
|
27
|
+
throw err
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
3
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
4
|
+
import { notificationTypes } from '../notifications'
|
|
5
|
+
import { StaffTeamMember, StaffTimeTask } from '../data/entities'
|
|
6
|
+
import { resolveAssignmentGraceDaysFromContainer } from '../lib/time-tracking/projectAssignment'
|
|
7
|
+
import { notifyProjectWork, resolveProjectWorkRecipients } from '../lib/time-tracking/workRecipients'
|
|
8
|
+
|
|
9
|
+
const logger = createLogger('staff').child({ component: 'subscribers/time-task-assignee-notification' })
|
|
10
|
+
|
|
11
|
+
const RELEASED_TYPE = 'staff.timesheets.time_task.released'
|
|
12
|
+
const ASSIGNED_TYPE = 'staff.timesheets.time_task.assigned'
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'staff.timesheets.time_task.assignee_changed',
|
|
16
|
+
persistent: true,
|
|
17
|
+
id: 'staff:time-task-assignee-notification',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type TaskAssigneeChangedPayload = {
|
|
21
|
+
id?: string | null
|
|
22
|
+
tenantId?: string | null
|
|
23
|
+
organizationId?: string | null
|
|
24
|
+
timeProjectId?: string | null
|
|
25
|
+
previousAssigneeStaffMemberId?: string | null
|
|
26
|
+
assigneeStaffMemberId?: string | null
|
|
27
|
+
changeKind?: 'default' | 'claim' | 'release' | 'manual' | null
|
|
28
|
+
actorUserId?: string | null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type ResolverContext = {
|
|
32
|
+
resolve: <T = unknown>(name: string) => T
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type AssigneeNotificationPlan = 'released' | 'assigned' | null
|
|
36
|
+
|
|
37
|
+
export function planAssigneeNotification(payload: TaskAssigneeChangedPayload): AssigneeNotificationPlan {
|
|
38
|
+
const kind = payload.changeKind ?? null
|
|
39
|
+
const next = payload.assigneeStaffMemberId ?? null
|
|
40
|
+
if (kind === 'release') return 'released'
|
|
41
|
+
if (kind === 'manual') return next ? 'assigned' : 'released'
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default async function handle(payload: TaskAssigneeChangedPayload, ctx: ResolverContext): Promise<void> {
|
|
46
|
+
try {
|
|
47
|
+
const plan = planAssigneeNotification(payload)
|
|
48
|
+
const taskId = payload.id ?? null
|
|
49
|
+
const tenantId = payload.tenantId ?? null
|
|
50
|
+
const organizationId = payload.organizationId ?? null
|
|
51
|
+
if (!plan || !taskId || !tenantId || !organizationId) return
|
|
52
|
+
const scope = { tenantId, organizationId }
|
|
53
|
+
const em = (ctx.resolve('em') as EntityManager).fork()
|
|
54
|
+
const task = await em.findOne(StaffTimeTask, { id: taskId, tenantId, organizationId, deletedAt: null })
|
|
55
|
+
if (!task) return
|
|
56
|
+
const build = {
|
|
57
|
+
bodyVariables: { reference: task.reference, title: task.title },
|
|
58
|
+
sourceEntityType: 'staff:staff_time_task',
|
|
59
|
+
sourceEntityId: task.id,
|
|
60
|
+
linkHref: `/backend/staff/time-tracking/board?projectId=${encodeURIComponent(task.timeProjectId)}&task=${encodeURIComponent(task.id)}`,
|
|
61
|
+
groupKey: `staff:time-task-${plan}:${task.id}`,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (plan === 'assigned') {
|
|
65
|
+
const typeDef = notificationTypes.find((type) => type.type === ASSIGNED_TYPE)
|
|
66
|
+
if (!typeDef || !task.assigneeStaffMemberId) return
|
|
67
|
+
const assignee = await findOneWithDecryption(
|
|
68
|
+
em,
|
|
69
|
+
StaffTeamMember,
|
|
70
|
+
{ id: task.assigneeStaffMemberId, tenantId, organizationId, deletedAt: null },
|
|
71
|
+
undefined,
|
|
72
|
+
scope,
|
|
73
|
+
)
|
|
74
|
+
const assigneeUserId = assignee?.userId ?? null
|
|
75
|
+
if (!assigneeUserId || assigneeUserId === (payload.actorUserId ?? null)) return
|
|
76
|
+
await notifyProjectWork(ctx, scope, { typeDef, recipients: { step: 1, userIds: [assigneeUserId] }, build })
|
|
77
|
+
return
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const typeDef = notificationTypes.find((type) => type.type === RELEASED_TYPE)
|
|
81
|
+
if (!typeDef) return
|
|
82
|
+
const graceDays = await resolveAssignmentGraceDaysFromContainer(ctx, tenantId)
|
|
83
|
+
const recipients = await resolveProjectWorkRecipients(em, scope, {
|
|
84
|
+
timeProjectId: task.timeProjectId,
|
|
85
|
+
actorUserId: payload.actorUserId ?? null,
|
|
86
|
+
graceDays,
|
|
87
|
+
})
|
|
88
|
+
const result = await notifyProjectWork(ctx, scope, { typeDef, recipients, build })
|
|
89
|
+
if (result.notifiedCount === 0) {
|
|
90
|
+
logger.warn('staff released-task notification reached nobody', {
|
|
91
|
+
tenantId,
|
|
92
|
+
organizationId,
|
|
93
|
+
timeProjectId: task.timeProjectId,
|
|
94
|
+
taskId: task.id,
|
|
95
|
+
step: result.step,
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
} catch (err) {
|
|
99
|
+
logger.error('staff task assignee notification failed', { err, taskId: payload.id ?? null })
|
|
100
|
+
throw err
|
|
101
|
+
}
|
|
102
|
+
}
|