@open-mercato/core 0.10.1-develop.7716.1.cefe7975df → 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
|
@@ -39,13 +39,13 @@ import { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from '@ope
|
|
|
39
39
|
import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
|
|
40
40
|
import { authorizeFeatures } from '@open-mercato/shared/security/featurePolicy'
|
|
41
41
|
import type { CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'
|
|
42
|
-
import { StaffTimeTask, StaffTimeTaskComment } from '../data/entities'
|
|
42
|
+
import { StaffTimeTask, StaffTimeTaskComment, type StaffTimeTaskCommentVisibility } from '../data/entities'
|
|
43
43
|
import { staffTimeTaskCommentCrudEvents } from '../lib/crud'
|
|
44
44
|
import {
|
|
45
45
|
staffTimeTaskCommentCreateSchema,
|
|
46
|
-
|
|
46
|
+
staffTimeTaskCommentUpdateRequestSchema,
|
|
47
47
|
type StaffTimeTaskCommentCreateInput,
|
|
48
|
-
type
|
|
48
|
+
type StaffTimeTaskCommentUpdateRequestInput,
|
|
49
49
|
} from '../data/validators'
|
|
50
50
|
import {
|
|
51
51
|
applyScopeToWhere,
|
|
@@ -96,6 +96,43 @@ const commentCrudIndexer: CrudIndexerConfig<StaffTimeTaskComment> = {
|
|
|
96
96
|
*/
|
|
97
97
|
const commentCrudEvents: CrudEventsConfig<StaffTimeTaskComment> = staffTimeTaskCommentCrudEvents
|
|
98
98
|
|
|
99
|
+
/**
|
|
100
|
+
* The comment CRUD events carry `portalVisible`: true when the comment is visible to
|
|
101
|
+
* the customer before OR after the change, so publishing, retracting and deleting a
|
|
102
|
+
* reply all refresh the portal. Internal notes never set it.
|
|
103
|
+
*/
|
|
104
|
+
function commentEvents(portalVisible: boolean): CrudEventsConfig<StaffTimeTaskComment> {
|
|
105
|
+
const base = staffTimeTaskCommentCrudEvents
|
|
106
|
+
return {
|
|
107
|
+
...base,
|
|
108
|
+
buildPayload: (context) => ({
|
|
109
|
+
...((base.buildPayload ? base.buildPayload(context) : {}) as Record<string, unknown>),
|
|
110
|
+
portalVisible,
|
|
111
|
+
}),
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export const TASK_COMMENT_CUSTOMER_IMMUTABLE_CODE = 'task_comment_customer_immutable'
|
|
116
|
+
export const TASK_COMMENT_VISIBILITY_INVALID_CODE = 'task_comment_visibility_invalid'
|
|
117
|
+
|
|
118
|
+
function customerCommentImmutableError(translate: Translate): CrudHttpError {
|
|
119
|
+
return new CrudHttpError(403, {
|
|
120
|
+
code: TASK_COMMENT_CUSTOMER_IMMUTABLE_CODE,
|
|
121
|
+
error: translate(
|
|
122
|
+
'staff.time_tracking.taskComments.errors.customerImmutable',
|
|
123
|
+
'Messages written by the customer cannot be edited or deleted.',
|
|
124
|
+
),
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function visibilityInvalidError(translate: Translate): CrudHttpError {
|
|
129
|
+
const message = translate(
|
|
130
|
+
'staff.time_tracking.taskComments.errors.visibilityPortalOnly',
|
|
131
|
+
'Only customer support tickets can carry replies visible to the customer.',
|
|
132
|
+
)
|
|
133
|
+
return new CrudHttpError(422, { code: TASK_COMMENT_VISIBILITY_INVALID_CODE, error: message, fieldErrors: { visibility: message } })
|
|
134
|
+
}
|
|
135
|
+
|
|
99
136
|
type Translate = (key: string, fallback: string) => string
|
|
100
137
|
|
|
101
138
|
type CommentSnapshot = {
|
|
@@ -105,6 +142,8 @@ type CommentSnapshot = {
|
|
|
105
142
|
taskId: string
|
|
106
143
|
body: string
|
|
107
144
|
authorUserId: string | null
|
|
145
|
+
visibility: StaffTimeTaskCommentVisibility
|
|
146
|
+
authorKind: string
|
|
108
147
|
createdAt: string | null
|
|
109
148
|
deletedAt: string | null
|
|
110
149
|
}
|
|
@@ -129,6 +168,8 @@ function toCommentSnapshot(comment: StaffTimeTaskComment): CommentSnapshot {
|
|
|
129
168
|
taskId: comment.taskId,
|
|
130
169
|
body: comment.body,
|
|
131
170
|
authorUserId: comment.authorUserId ?? null,
|
|
171
|
+
visibility: comment.visibility ?? 'internal',
|
|
172
|
+
authorKind: comment.authorKind ?? 'staff',
|
|
132
173
|
createdAt: comment.createdAt ? comment.createdAt.toISOString() : null,
|
|
133
174
|
deletedAt: comment.deletedAt ? comment.deletedAt.toISOString() : null,
|
|
134
175
|
}
|
|
@@ -211,6 +252,7 @@ async function requireEditableComment(
|
|
|
211
252
|
ctx: CommandRuntimeContext,
|
|
212
253
|
translate: Translate,
|
|
213
254
|
): Promise<void> {
|
|
255
|
+
if (comment.authorKind === 'customer') throw customerCommentImmutableError(translate)
|
|
214
256
|
const actorId = stampAuthorUserId(ctx)
|
|
215
257
|
if (actorId && comment.authorUserId === actorId) return
|
|
216
258
|
if (await callerCanManageAll(ctx)) return
|
|
@@ -257,7 +299,10 @@ const createTaskCommentCommand: CommandHandler<
|
|
|
257
299
|
await withAtomicFlush(
|
|
258
300
|
em,
|
|
259
301
|
[
|
|
260
|
-
() =>
|
|
302
|
+
async () => {
|
|
303
|
+
const task = await requireTaskInScope(em, parsed.taskId, scope, translate)
|
|
304
|
+
if (parsed.visibility === 'customer' && task.source !== 'portal') throw visibilityInvalidError(translate)
|
|
305
|
+
},
|
|
261
306
|
() => {
|
|
262
307
|
created = em.create(StaffTimeTaskComment, {
|
|
263
308
|
tenantId: parsed.tenantId,
|
|
@@ -265,6 +310,8 @@ const createTaskCommentCommand: CommandHandler<
|
|
|
265
310
|
taskId: parsed.taskId,
|
|
266
311
|
body: parsed.body,
|
|
267
312
|
authorUserId,
|
|
313
|
+
visibility: parsed.visibility ?? 'internal',
|
|
314
|
+
authorKind: 'staff',
|
|
268
315
|
createdAt: new Date(),
|
|
269
316
|
updatedAt: new Date(),
|
|
270
317
|
deletedAt: null,
|
|
@@ -283,7 +330,7 @@ const createTaskCommentCommand: CommandHandler<
|
|
|
283
330
|
action: 'created',
|
|
284
331
|
entity: record,
|
|
285
332
|
identifiers: { id: record.id, organizationId: record.organizationId, tenantId: record.tenantId },
|
|
286
|
-
events:
|
|
333
|
+
events: commentEvents(record.visibility === 'customer'),
|
|
287
334
|
indexer: commentCrudIndexer,
|
|
288
335
|
})
|
|
289
336
|
|
|
@@ -340,19 +387,19 @@ const createTaskCommentCommand: CommandHandler<
|
|
|
340
387
|
action: 'deleted',
|
|
341
388
|
entity: comment,
|
|
342
389
|
identifiers: { id: comment.id, organizationId: comment.organizationId, tenantId: comment.tenantId },
|
|
343
|
-
events:
|
|
390
|
+
events: commentEvents(comment.visibility === 'customer'),
|
|
344
391
|
indexer: commentCrudIndexer,
|
|
345
392
|
})
|
|
346
393
|
},
|
|
347
394
|
}
|
|
348
395
|
|
|
349
396
|
const updateTaskCommentCommand: CommandHandler<
|
|
350
|
-
|
|
397
|
+
StaffTimeTaskCommentUpdateRequestInput,
|
|
351
398
|
{ commentId: string; taskId: string }
|
|
352
399
|
> = {
|
|
353
400
|
id: staffTimeTaskCommentCommandIds.update,
|
|
354
401
|
async prepare(rawInput, ctx) {
|
|
355
|
-
const parsed =
|
|
402
|
+
const parsed = staffTimeTaskCommentUpdateRequestSchema.safeParse(rawInput)
|
|
356
403
|
if (!parsed.success) return {}
|
|
357
404
|
const em = ctx.container.resolve('em') as EntityManager
|
|
358
405
|
const before = await loadCommentSnapshot(em, parsed.data.id, staffSnapshotScopeFromContext(ctx))
|
|
@@ -360,7 +407,7 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
360
407
|
return { before: { snapshot: before } }
|
|
361
408
|
},
|
|
362
409
|
async execute(rawInput, ctx) {
|
|
363
|
-
const parsed =
|
|
410
|
+
const parsed = staffTimeTaskCommentUpdateRequestSchema.parse(rawInput)
|
|
364
411
|
const { translate } = await resolveTranslations()
|
|
365
412
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
366
413
|
const scope = commandActorScope(ctx)
|
|
@@ -374,12 +421,18 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
374
421
|
ensureOrganizationScope(ctx, comment.organizationId)
|
|
375
422
|
assertCommentVersion(ctx, comment)
|
|
376
423
|
await requireEditableComment(comment, ctx, translate)
|
|
424
|
+
const visibilityBefore = comment.visibility ?? 'internal'
|
|
425
|
+
if (parsed.visibility === 'customer' && visibilityBefore !== 'customer') {
|
|
426
|
+
const task = await requireTaskInScope(em, comment.taskId, scope, translate)
|
|
427
|
+
if (task.source !== 'portal') throw visibilityInvalidError(translate)
|
|
428
|
+
}
|
|
377
429
|
|
|
378
430
|
await withAtomicFlush(
|
|
379
431
|
em,
|
|
380
432
|
[
|
|
381
433
|
() => {
|
|
382
|
-
comment.body = parsed.body
|
|
434
|
+
if (parsed.body !== undefined) comment.body = parsed.body
|
|
435
|
+
if (parsed.visibility !== undefined) comment.visibility = parsed.visibility
|
|
383
436
|
comment.updatedAt = new Date()
|
|
384
437
|
},
|
|
385
438
|
],
|
|
@@ -391,7 +444,7 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
391
444
|
action: 'updated',
|
|
392
445
|
entity: comment,
|
|
393
446
|
identifiers: { id: comment.id, organizationId: comment.organizationId, tenantId: comment.tenantId },
|
|
394
|
-
events:
|
|
447
|
+
events: commentEvents(visibilityBefore === 'customer' || comment.visibility === 'customer'),
|
|
395
448
|
indexer: commentCrudIndexer,
|
|
396
449
|
})
|
|
397
450
|
|
|
@@ -417,7 +470,7 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
417
470
|
changes: buildChanges(
|
|
418
471
|
before as unknown as Record<string, unknown>,
|
|
419
472
|
after as unknown as Record<string, unknown>,
|
|
420
|
-
['body'],
|
|
473
|
+
['body', 'visibility'],
|
|
421
474
|
),
|
|
422
475
|
payload: {
|
|
423
476
|
undo: { before, after } satisfies CommentUndoPayload,
|
|
@@ -440,6 +493,7 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
440
493
|
[
|
|
441
494
|
() => {
|
|
442
495
|
comment.body = before.body
|
|
496
|
+
comment.visibility = before.visibility ?? 'internal'
|
|
443
497
|
comment.updatedAt = new Date()
|
|
444
498
|
},
|
|
445
499
|
],
|
|
@@ -451,7 +505,7 @@ const updateTaskCommentCommand: CommandHandler<
|
|
|
451
505
|
action: 'updated',
|
|
452
506
|
entity: comment,
|
|
453
507
|
identifiers: { id: comment.id, organizationId: comment.organizationId, tenantId: comment.tenantId },
|
|
454
|
-
events:
|
|
508
|
+
events: commentEvents(true),
|
|
455
509
|
indexer: commentCrudIndexer,
|
|
456
510
|
})
|
|
457
511
|
},
|
|
@@ -505,7 +559,7 @@ const deleteTaskCommentCommand: CommandHandler<{ id?: string }, { commentId: str
|
|
|
505
559
|
action: 'deleted',
|
|
506
560
|
entity: comment,
|
|
507
561
|
identifiers: { id: comment.id, organizationId: comment.organizationId, tenantId: comment.tenantId },
|
|
508
|
-
events:
|
|
562
|
+
events: commentEvents(comment.visibility === 'customer'),
|
|
509
563
|
indexer: commentCrudIndexer,
|
|
510
564
|
})
|
|
511
565
|
|
|
@@ -551,6 +605,7 @@ const deleteTaskCommentCommand: CommandHandler<{ id?: string }, { commentId: str
|
|
|
551
605
|
taskId: before.taskId,
|
|
552
606
|
body: before.body,
|
|
553
607
|
authorUserId: before.authorUserId,
|
|
608
|
+
visibility: before.visibility ?? 'internal',
|
|
554
609
|
createdAt: before.createdAt ? new Date(before.createdAt) : new Date(),
|
|
555
610
|
updatedAt: new Date(),
|
|
556
611
|
deletedAt: null,
|
|
@@ -572,7 +627,7 @@ const deleteTaskCommentCommand: CommandHandler<{ id?: string }, { commentId: str
|
|
|
572
627
|
action: 'created',
|
|
573
628
|
entity: comment,
|
|
574
629
|
identifiers: { id: before.id, organizationId: before.organizationId, tenantId: before.tenantId },
|
|
575
|
-
events:
|
|
630
|
+
events: commentEvents(before.visibility === 'customer'),
|
|
576
631
|
indexer: commentCrudIndexer,
|
|
577
632
|
})
|
|
578
633
|
},
|
|
@@ -34,13 +34,15 @@ import { registerCommand } from '@open-mercato/shared/lib/commands'
|
|
|
34
34
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
35
35
|
import { enforceCommandOptimisticLockWithGuards } from '@open-mercato/shared/lib/crud/optimistic-lock-command'
|
|
36
36
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
37
|
+
import { getTelemetryRuntime } from '@open-mercato/shared/lib/telemetry/runtime'
|
|
37
38
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
38
39
|
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
39
40
|
import { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'
|
|
41
|
+
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
40
42
|
import { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'
|
|
41
43
|
import type { CrudEventsConfig, CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'
|
|
42
44
|
import type { DataEngine } from '@open-mercato/shared/lib/data/engine'
|
|
43
|
-
import { StaffTeamMember, StaffTimeProject, StaffTimeTask, StaffTimeTaskStatus } from '../data/entities'
|
|
45
|
+
import { StaffSupportTicket, StaffTeamMember, StaffTimeProject, StaffTimeTask, StaffTimeTaskStatus } from '../data/entities'
|
|
44
46
|
import {
|
|
45
47
|
staffTimeTaskCreateSchema,
|
|
46
48
|
staffTimeTaskStatusChangeSchema,
|
|
@@ -67,7 +69,9 @@ import {
|
|
|
67
69
|
commandInputScope,
|
|
68
70
|
ensureOrganizationScope,
|
|
69
71
|
ensureTenantScope,
|
|
72
|
+
explicitStaffCommandScope,
|
|
70
73
|
extractUndoPayload,
|
|
74
|
+
lockLiveProjectForWrite,
|
|
71
75
|
scopeForDecryption,
|
|
72
76
|
scopedStaffSnapshotWhere,
|
|
73
77
|
staffSnapshotScopeFromContext,
|
|
@@ -102,7 +106,7 @@ export const TASK_REFERENCE_CONFLICT_CODE = 'task_reference_conflict'
|
|
|
102
106
|
|
|
103
107
|
const logger = createLogger('staff').child({ component: 'commands/timesheets-tasks' })
|
|
104
108
|
|
|
105
|
-
const taskCrudIndexer: CrudIndexerConfig<StaffTimeTask> = {
|
|
109
|
+
export const taskCrudIndexer: CrudIndexerConfig<StaffTimeTask> = {
|
|
106
110
|
entityType: 'staff:staff_time_task',
|
|
107
111
|
}
|
|
108
112
|
|
|
@@ -111,7 +115,7 @@ const taskCrudIndexer: CrudIndexerConfig<StaffTimeTask> = {
|
|
|
111
115
|
* lifecycle `…status_changed` event belongs to the dedicated status endpoint that
|
|
112
116
|
* owns the drag-and-drop move, not to these generic writes.
|
|
113
117
|
*/
|
|
114
|
-
const taskCrudEvents: CrudEventsConfig<StaffTimeTask> = {
|
|
118
|
+
export const taskCrudEvents: CrudEventsConfig<StaffTimeTask> = {
|
|
115
119
|
module: 'staff',
|
|
116
120
|
entity: 'timesheets.time_task',
|
|
117
121
|
persistent: true,
|
|
@@ -136,7 +140,7 @@ const taskCrudEvents: CrudEventsConfig<StaffTimeTask> = {
|
|
|
136
140
|
* "changed by someone else" until the entry expired. `ENABLE_CRUD_API_CACHE` off
|
|
137
141
|
* hides it; the ephemeral QA and integration environments run with it on.
|
|
138
142
|
*/
|
|
139
|
-
const TASK_LIST_CACHE_RESOURCE = `${taskCrudEvents.module}.${taskCrudEvents.entity}`
|
|
143
|
+
export const TASK_LIST_CACHE_RESOURCE = `${taskCrudEvents.module}.${taskCrudEvents.entity}`
|
|
140
144
|
|
|
141
145
|
type Translate = (key: string, fallback: string) => string
|
|
142
146
|
|
|
@@ -163,6 +167,8 @@ type TaskUndoPayload = {
|
|
|
163
167
|
after?: TaskSnapshot | null
|
|
164
168
|
/** Children the delete took with it, so undo can put the whole set back. */
|
|
165
169
|
cascadedChildren?: TaskSnapshot[] | null
|
|
170
|
+
/** Support tickets this delete soft-deleted; undo restores exactly these and no others. */
|
|
171
|
+
cascadedSupportTicketIds?: string[] | null
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
const DIFFED_FIELDS = [
|
|
@@ -323,10 +329,7 @@ async function requireProject(
|
|
|
323
329
|
scope: StaffCommandScope,
|
|
324
330
|
translate: Translate,
|
|
325
331
|
): Promise<StaffTimeProject> {
|
|
326
|
-
const project = await em
|
|
327
|
-
StaffTimeProject,
|
|
328
|
-
applyScopeToWhere<StaffTimeProject>({ id: timeProjectId, deletedAt: null }, scope),
|
|
329
|
-
)
|
|
332
|
+
const project = await lockLiveProjectForWrite(em, timeProjectId, scope)
|
|
330
333
|
if (!project) throw projectNotFoundError(translate)
|
|
331
334
|
return project
|
|
332
335
|
}
|
|
@@ -336,7 +339,7 @@ async function requireProject(
|
|
|
336
339
|
* otherwise the project's `is_default` entry point. The board invariants guarantee one
|
|
337
340
|
* exists; the positional fallback only covers a board repaired by hand.
|
|
338
341
|
*/
|
|
339
|
-
async function resolveTaskStatus(
|
|
342
|
+
export async function resolveTaskStatus(
|
|
340
343
|
em: EntityManager,
|
|
341
344
|
timeProjectId: string,
|
|
342
345
|
requestedStatusId: string | null | undefined,
|
|
@@ -408,7 +411,7 @@ async function requireStaffMember(
|
|
|
408
411
|
* Order within a column, on the same gap grid the columns themselves use: a drop
|
|
409
412
|
* between two cards writes one row instead of renumbering the stack.
|
|
410
413
|
*/
|
|
411
|
-
async function nextTaskPosition(
|
|
414
|
+
export async function nextTaskPosition(
|
|
412
415
|
em: EntityManager,
|
|
413
416
|
timeProjectId: string,
|
|
414
417
|
taskStatusId: string,
|
|
@@ -427,7 +430,7 @@ async function nextTaskPosition(
|
|
|
427
430
|
* the next task reuse that reference — and a closed report quoting the old one would
|
|
428
431
|
* suddenly read as the new one.
|
|
429
432
|
*/
|
|
430
|
-
async function readHighestSequenceNumber(
|
|
433
|
+
export async function readHighestSequenceNumber(
|
|
431
434
|
em: EntityManager,
|
|
432
435
|
timeProjectId: string,
|
|
433
436
|
scope: StaffCommandScope,
|
|
@@ -457,7 +460,7 @@ function assertNoProjectMove(rawInput: unknown, task: StaffTimeTask, translate:
|
|
|
457
460
|
})
|
|
458
461
|
}
|
|
459
462
|
|
|
460
|
-
function applyStatusToTask(task: StaffTimeTask, status: StaffTimeTaskStatus, now: Date): void {
|
|
463
|
+
export function applyStatusToTask(task: StaffTimeTask, status: StaffTimeTaskStatus, now: Date): void {
|
|
461
464
|
task.taskStatusId = status.id
|
|
462
465
|
// Done-ness comes from the column, never from a boolean on the task: landing on a
|
|
463
466
|
// terminal column closes it, leaving one re-opens it.
|
|
@@ -622,6 +625,33 @@ const createTaskCommand: CommandHandler<StaffTimeTaskCreateInput, { taskId: stri
|
|
|
622
625
|
},
|
|
623
626
|
}
|
|
624
627
|
|
|
628
|
+
export type TaskAssigneeChangeReason = 'default' | 'claim' | 'release' | 'manual'
|
|
629
|
+
|
|
630
|
+
export function emitTaskAssigneeChanged(
|
|
631
|
+
task: Pick<StaffTimeTask, 'id' | 'tenantId' | 'organizationId' | 'timeProjectId' | 'assigneeStaffMemberId'>,
|
|
632
|
+
previousAssigneeStaffMemberId: string | null,
|
|
633
|
+
changeKind: TaskAssigneeChangeReason,
|
|
634
|
+
actorUserId: string | null = null,
|
|
635
|
+
): void {
|
|
636
|
+
void emitStaffEvent(
|
|
637
|
+
'staff.timesheets.time_task.assignee_changed',
|
|
638
|
+
{
|
|
639
|
+
id: task.id,
|
|
640
|
+
tenantId: task.tenantId,
|
|
641
|
+
organizationId: task.organizationId,
|
|
642
|
+
timeProjectId: task.timeProjectId,
|
|
643
|
+
previousAssigneeStaffMemberId,
|
|
644
|
+
assigneeStaffMemberId: task.assigneeStaffMemberId ?? null,
|
|
645
|
+
changeKind,
|
|
646
|
+
actorUserId,
|
|
647
|
+
},
|
|
648
|
+
{ persistent: true },
|
|
649
|
+
).catch((err) => {
|
|
650
|
+
logger.error('staff.timesheets.time_task.assignee_changed emit failed', { err, taskId: task.id })
|
|
651
|
+
getTelemetryRuntime()?.reportError(err, { module: 'staff', code: 'staff.task_assignee_changed_emit_failed' })
|
|
652
|
+
})
|
|
653
|
+
}
|
|
654
|
+
|
|
625
655
|
const updateTaskCommand: CommandHandler<StaffTimeTaskUpdateInput, { taskId: string }> = {
|
|
626
656
|
id: staffTimeTaskCommandIds.update,
|
|
627
657
|
async prepare(rawInput, ctx) {
|
|
@@ -650,6 +680,7 @@ const updateTaskCommand: CommandHandler<StaffTimeTaskUpdateInput, { taskId: stri
|
|
|
650
680
|
let targetStatus: StaffTimeTaskStatus | null = null
|
|
651
681
|
let targetParentTaskId: string | null | undefined
|
|
652
682
|
let targetAssigneeStaffMemberId: string | null | undefined
|
|
683
|
+
const previousAssigneeStaffMemberId = task.assigneeStaffMemberId ?? null
|
|
653
684
|
|
|
654
685
|
await withAtomicFlush(
|
|
655
686
|
em,
|
|
@@ -707,6 +738,11 @@ const updateTaskCommand: CommandHandler<StaffTimeTaskUpdateInput, { taskId: stri
|
|
|
707
738
|
indexer: taskCrudIndexer,
|
|
708
739
|
})
|
|
709
740
|
|
|
741
|
+
const nextAssigneeStaffMemberId = task.assigneeStaffMemberId ?? null
|
|
742
|
+
if (targetAssigneeStaffMemberId !== undefined && nextAssigneeStaffMemberId !== previousAssigneeStaffMemberId) {
|
|
743
|
+
emitTaskAssigneeChanged(task, previousAssigneeStaffMemberId, 'manual', ctx.auth?.sub ?? null)
|
|
744
|
+
}
|
|
745
|
+
|
|
710
746
|
return { taskId: task.id }
|
|
711
747
|
},
|
|
712
748
|
buildLog: async ({ snapshots, ctx }) => {
|
|
@@ -766,7 +802,13 @@ const updateTaskCommand: CommandHandler<StaffTimeTaskUpdateInput, { taskId: stri
|
|
|
766
802
|
},
|
|
767
803
|
}
|
|
768
804
|
|
|
769
|
-
|
|
805
|
+
export type StaffTimeTaskDeleteResult = {
|
|
806
|
+
taskId: string
|
|
807
|
+
childIds: string[]
|
|
808
|
+
supportTicketIds: string[]
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const deleteTaskCommand: CommandHandler<{ id?: string }, StaffTimeTaskDeleteResult> = {
|
|
770
812
|
id: staffTimeTaskCommandIds.delete,
|
|
771
813
|
async prepare(input, ctx) {
|
|
772
814
|
const id = input?.id
|
|
@@ -798,6 +840,8 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
798
840
|
|
|
799
841
|
let children: StaffTimeTask[] = []
|
|
800
842
|
let childIds: string[] = []
|
|
843
|
+
let supportTickets: StaffSupportTicket[] = []
|
|
844
|
+
const supportTicketIds: string[] = []
|
|
801
845
|
|
|
802
846
|
await withAtomicFlush(
|
|
803
847
|
em,
|
|
@@ -811,6 +855,18 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
811
855
|
StaffTimeTask,
|
|
812
856
|
applyScopeToWhere<StaffTimeTask>({ parentTaskId: task.id, deletedAt: null }, scope),
|
|
813
857
|
)
|
|
858
|
+
supportTickets = await findWithDecryption(
|
|
859
|
+
em,
|
|
860
|
+
StaffSupportTicket,
|
|
861
|
+
{
|
|
862
|
+
taskId: { $in: [task.id, ...children.map((child) => child.id)] },
|
|
863
|
+
tenantId: task.tenantId,
|
|
864
|
+
organizationId: task.organizationId,
|
|
865
|
+
deletedAt: null,
|
|
866
|
+
},
|
|
867
|
+
undefined,
|
|
868
|
+
{ tenantId: task.tenantId, organizationId: task.organizationId },
|
|
869
|
+
)
|
|
814
870
|
},
|
|
815
871
|
() => {
|
|
816
872
|
const plan = planTaskSoftDelete(task, children)
|
|
@@ -825,6 +881,13 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
825
881
|
child.deletedAt = now
|
|
826
882
|
child.updatedAt = now
|
|
827
883
|
}
|
|
884
|
+
const removedTaskIds = new Set([task.id, ...childIds])
|
|
885
|
+
for (const ticket of supportTickets) {
|
|
886
|
+
if (!removedTaskIds.has(ticket.taskId)) continue
|
|
887
|
+
ticket.deletedAt = now
|
|
888
|
+
ticket.updatedAt = now
|
|
889
|
+
supportTicketIds.push(ticket.id)
|
|
890
|
+
}
|
|
828
891
|
// Time entries are untouched on purpose: a closed report still has to
|
|
829
892
|
// resolve this task's label months after it was removed from the board.
|
|
830
893
|
},
|
|
@@ -844,9 +907,9 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
844
907
|
})
|
|
845
908
|
}
|
|
846
909
|
|
|
847
|
-
return { taskId: task.id, childIds }
|
|
910
|
+
return { taskId: task.id, childIds, supportTicketIds }
|
|
848
911
|
},
|
|
849
|
-
buildLog: async ({ snapshots }) => {
|
|
912
|
+
buildLog: async ({ snapshots, result }) => {
|
|
850
913
|
const prepared = snapshots.before as
|
|
851
914
|
| { snapshot?: TaskSnapshot; cascadedChildren?: TaskSnapshot[] }
|
|
852
915
|
| undefined
|
|
@@ -864,6 +927,7 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
864
927
|
undo: {
|
|
865
928
|
before,
|
|
866
929
|
cascadedChildren: prepared?.cascadedChildren ?? null,
|
|
930
|
+
cascadedSupportTicketIds: result?.supportTicketIds ?? [],
|
|
867
931
|
} satisfies TaskUndoPayload,
|
|
868
932
|
},
|
|
869
933
|
}
|
|
@@ -876,16 +940,39 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
876
940
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
877
941
|
const ids = [before.id, ...(payload?.cascadedChildren ?? []).map((child) => child.id)]
|
|
878
942
|
const restored: StaffTimeTask[] = []
|
|
943
|
+
const restoredTickets: StaffSupportTicket[] = []
|
|
944
|
+
const ticketIds = payload?.cascadedSupportTicketIds ?? []
|
|
945
|
+
const { translate } = await resolveTranslations()
|
|
879
946
|
|
|
880
947
|
await withAtomicFlush(
|
|
881
948
|
em,
|
|
882
949
|
[
|
|
883
950
|
async () => {
|
|
951
|
+
const project = await lockLiveProjectForWrite(
|
|
952
|
+
em,
|
|
953
|
+
before.timeProjectId,
|
|
954
|
+
explicitStaffCommandScope(before.tenantId, before.organizationId),
|
|
955
|
+
)
|
|
956
|
+
if (!project) throw projectNotFoundError(translate)
|
|
884
957
|
const tasks = await em.find(StaffTimeTask, {
|
|
885
958
|
id: { $in: ids },
|
|
886
959
|
...snapshotScopeWhere(snapshotScope),
|
|
887
960
|
})
|
|
888
961
|
restored.push(...tasks)
|
|
962
|
+
if (ticketIds.length === 0) return
|
|
963
|
+
const tickets = await findWithDecryption(
|
|
964
|
+
em,
|
|
965
|
+
StaffSupportTicket,
|
|
966
|
+
{
|
|
967
|
+
id: { $in: ticketIds },
|
|
968
|
+
taskId: { $in: ids },
|
|
969
|
+
...snapshotScopeWhere(snapshotScope),
|
|
970
|
+
deletedAt: { $ne: null },
|
|
971
|
+
},
|
|
972
|
+
undefined,
|
|
973
|
+
{ tenantId: before.tenantId, organizationId: before.organizationId },
|
|
974
|
+
)
|
|
975
|
+
restoredTickets.push(...tickets)
|
|
889
976
|
},
|
|
890
977
|
() => {
|
|
891
978
|
// Undo restores the whole set the cascade removed, not just the parent.
|
|
@@ -893,6 +980,10 @@ const deleteTaskCommand: CommandHandler<{ id?: string }, { taskId: string; child
|
|
|
893
980
|
task.deletedAt = null
|
|
894
981
|
task.updatedAt = new Date()
|
|
895
982
|
}
|
|
983
|
+
for (const ticket of restoredTickets) {
|
|
984
|
+
ticket.deletedAt = null
|
|
985
|
+
ticket.updatedAt = new Date()
|
|
986
|
+
}
|
|
896
987
|
},
|
|
897
988
|
],
|
|
898
989
|
{ transaction: true, label: `${staffTimeTaskCommandIds.delete}.undo` },
|