@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
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
import { LockMode } from "@mikro-orm/core";
|
|
2
|
+
import { registerCommand } from "@open-mercato/shared/lib/commands";
|
|
3
|
+
import { CrudHttpError, isUniqueViolation } from "@open-mercato/shared/lib/crud/errors";
|
|
4
|
+
import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
5
|
+
import { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from "@open-mercato/shared/lib/commands/helpers";
|
|
6
|
+
import { withAtomicFlush } from "@open-mercato/shared/lib/commands/flush";
|
|
7
|
+
import { StaffSupportRoutingRule, StaffTimeProject, StaffTimeTask, StaffTimeTaskStatus } from "../data/entities.js";
|
|
8
|
+
import { staffTimeProjectCrudEvents, staffTimeProjectCrudIndexer } from "../lib/crud.js";
|
|
9
|
+
import {
|
|
10
|
+
staffSupportFallbackProjectCreateSchema,
|
|
11
|
+
staffSupportRoutingRuleCreateSchema,
|
|
12
|
+
staffSupportRoutingRuleUpdateSchema
|
|
13
|
+
} from "../data/validators.js";
|
|
14
|
+
import { findSupportTicketCategory } from "../lib/support/dictionaries.js";
|
|
15
|
+
import { ensureFallbackProjectAndRule, resolveContainerProjectCodeGenerator } from "../lib/support/seedDefaults.js";
|
|
16
|
+
import {
|
|
17
|
+
applyScopeToWhere,
|
|
18
|
+
commandActorScope,
|
|
19
|
+
commandInputScope,
|
|
20
|
+
ensureOrganizationScope,
|
|
21
|
+
ensureTenantScope,
|
|
22
|
+
explicitStaffCommandScope,
|
|
23
|
+
extractUndoPayload,
|
|
24
|
+
lockLiveProjectForWrite,
|
|
25
|
+
scopedStaffSnapshotWhere,
|
|
26
|
+
staffSnapshotScopeFromContext,
|
|
27
|
+
staffSnapshotScopeFromSnapshot
|
|
28
|
+
} from "./shared.js";
|
|
29
|
+
const staffSupportRoutingRuleCommandIds = {
|
|
30
|
+
create: "staff.support.routing_rules.create",
|
|
31
|
+
update: "staff.support.routing_rules.update",
|
|
32
|
+
delete: "staff.support.routing_rules.delete",
|
|
33
|
+
createFallbackProject: "staff.support.routing_rules.create_fallback_project"
|
|
34
|
+
};
|
|
35
|
+
const SUPPORT_ROUTING_RULE_RESOURCE_KIND = "staff.support.routing_rule";
|
|
36
|
+
const routingRuleIndexer = {
|
|
37
|
+
entityType: "staff:staff_support_routing_rule"
|
|
38
|
+
};
|
|
39
|
+
function toSnapshot(rule) {
|
|
40
|
+
return {
|
|
41
|
+
id: rule.id,
|
|
42
|
+
tenantId: rule.tenantId,
|
|
43
|
+
organizationId: rule.organizationId,
|
|
44
|
+
categoryValue: rule.categoryValue ?? null,
|
|
45
|
+
timeProjectId: rule.timeProjectId,
|
|
46
|
+
isActive: rule.isActive,
|
|
47
|
+
deletedAt: rule.deletedAt ? rule.deletedAt.toISOString() : null
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async function loadSnapshot(em, id, scope) {
|
|
51
|
+
const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(id, scope));
|
|
52
|
+
return rule ? toSnapshot(rule) : null;
|
|
53
|
+
}
|
|
54
|
+
function notFoundError(translate) {
|
|
55
|
+
return new CrudHttpError(404, {
|
|
56
|
+
error: translate("staff.support.errors.routingRuleNotFound", "Routing rule not found.")
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function fallbackRequiredError(translate) {
|
|
60
|
+
return new CrudHttpError(422, {
|
|
61
|
+
code: "support_fallback_rule_required",
|
|
62
|
+
error: translate(
|
|
63
|
+
"staff.support.errors.fallbackRuleRequired",
|
|
64
|
+
"The fallback rule cannot be deleted or paused. Point it at another project instead."
|
|
65
|
+
)
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function duplicateRuleError(translate, isFallback) {
|
|
69
|
+
const message = isFallback ? translate("staff.support.errors.fallbackRuleExists", "This organization already has a fallback rule.") : translate("staff.support.errors.categoryRuleExists", "This category already has a routing rule.");
|
|
70
|
+
return new CrudHttpError(409, {
|
|
71
|
+
code: "support_routing_rule_duplicate",
|
|
72
|
+
error: message,
|
|
73
|
+
fieldErrors: { categoryValue: message }
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
async function requireRoutableProject(em, timeProjectId, scope, translate, options = {}) {
|
|
77
|
+
const project = await lockLiveProjectForWrite(em, timeProjectId, explicitStaffCommandScope(scope.tenantId, scope.organizationId));
|
|
78
|
+
if (!project) {
|
|
79
|
+
const message = translate("staff.support.errors.projectNotFound", "The selected project does not exist in this organization.");
|
|
80
|
+
throw new CrudHttpError(422, { code: "support_project_not_found", error: message, fieldErrors: { timeProjectId: message } });
|
|
81
|
+
}
|
|
82
|
+
if (options.requireDefaultStatus === false) return;
|
|
83
|
+
const defaultStatus = await em.findOne(
|
|
84
|
+
StaffTimeTaskStatus,
|
|
85
|
+
{ timeProjectId, tenantId: scope.tenantId, organizationId: scope.organizationId, isDefault: true, deletedAt: null },
|
|
86
|
+
{ fields: ["id"] }
|
|
87
|
+
);
|
|
88
|
+
if (!defaultStatus) {
|
|
89
|
+
const message = translate(
|
|
90
|
+
"staff.support.errors.projectHasNoDefaultStatus",
|
|
91
|
+
"The selected project has no default task status, so tickets cannot be filed on its board."
|
|
92
|
+
);
|
|
93
|
+
throw new CrudHttpError(422, { code: "support_project_no_default_status", error: message, fieldErrors: { timeProjectId: message } });
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function requireKnownCategory(em, categoryValue, scope, translate) {
|
|
97
|
+
const category = await findSupportTicketCategory(em, scope, categoryValue);
|
|
98
|
+
if (category) return;
|
|
99
|
+
const message = translate("staff.support.errors.categoryNotFound", "This category does not exist in the support categories dictionary.");
|
|
100
|
+
throw new CrudHttpError(422, { code: "support_category_not_found", error: message, fieldErrors: { categoryValue: message } });
|
|
101
|
+
}
|
|
102
|
+
async function emitRuleSideEffects(ctx, action, rule) {
|
|
103
|
+
await emitCrudSideEffects({
|
|
104
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
105
|
+
action,
|
|
106
|
+
entity: rule,
|
|
107
|
+
identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },
|
|
108
|
+
indexer: routingRuleIndexer
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const createRoutingRuleCommand = {
|
|
112
|
+
id: staffSupportRoutingRuleCommandIds.create,
|
|
113
|
+
async execute(rawInput, ctx) {
|
|
114
|
+
const parsed = staffSupportRoutingRuleCreateSchema.parse(rawInput);
|
|
115
|
+
const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
|
|
116
|
+
const { translate } = await resolveTranslations();
|
|
117
|
+
const target = { tenantId: parsed.tenantId, organizationId: parsed.organizationId };
|
|
118
|
+
const categoryValue = parsed.categoryValue ?? null;
|
|
119
|
+
const isFallback = categoryValue === null;
|
|
120
|
+
if (isFallback && parsed.isActive === false) throw fallbackRequiredError(translate);
|
|
121
|
+
const em = ctx.container.resolve("em").fork();
|
|
122
|
+
let created = null;
|
|
123
|
+
try {
|
|
124
|
+
await withAtomicFlush(
|
|
125
|
+
em,
|
|
126
|
+
[
|
|
127
|
+
async () => {
|
|
128
|
+
await requireRoutableProject(em, parsed.timeProjectId, target, translate);
|
|
129
|
+
if (categoryValue !== null) await requireKnownCategory(em, categoryValue, target, translate);
|
|
130
|
+
const duplicate = await em.findOne(
|
|
131
|
+
StaffSupportRoutingRule,
|
|
132
|
+
applyScopeToWhere({ categoryValue, deletedAt: null }, scope),
|
|
133
|
+
{ fields: ["id"] }
|
|
134
|
+
);
|
|
135
|
+
if (duplicate) throw duplicateRuleError(translate, isFallback);
|
|
136
|
+
},
|
|
137
|
+
() => {
|
|
138
|
+
created = em.create(StaffSupportRoutingRule, {
|
|
139
|
+
tenantId: parsed.tenantId,
|
|
140
|
+
organizationId: parsed.organizationId,
|
|
141
|
+
categoryValue,
|
|
142
|
+
timeProjectId: parsed.timeProjectId,
|
|
143
|
+
isActive: isFallback ? true : parsed.isActive ?? true,
|
|
144
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
145
|
+
updatedAt: /* @__PURE__ */ new Date(),
|
|
146
|
+
deletedAt: null
|
|
147
|
+
});
|
|
148
|
+
em.persist(created);
|
|
149
|
+
}
|
|
150
|
+
],
|
|
151
|
+
{ transaction: true, label: staffSupportRoutingRuleCommandIds.create }
|
|
152
|
+
);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (isUniqueViolation(err)) throw duplicateRuleError(translate, isFallback);
|
|
155
|
+
throw err;
|
|
156
|
+
}
|
|
157
|
+
const record = created;
|
|
158
|
+
if (!record) throw notFoundError(translate);
|
|
159
|
+
await emitRuleSideEffects(ctx, "created", record);
|
|
160
|
+
return { ruleId: record.id };
|
|
161
|
+
},
|
|
162
|
+
buildLog: async ({ result, ctx }) => {
|
|
163
|
+
const em = ctx.container.resolve("em").fork();
|
|
164
|
+
const snapshot = await loadSnapshot(em, result.ruleId, staffSnapshotScopeFromContext(ctx));
|
|
165
|
+
if (!snapshot) return null;
|
|
166
|
+
const { translate } = await resolveTranslations();
|
|
167
|
+
return {
|
|
168
|
+
actionLabel: translate("staff.audit.support.routingRules.create", "Create support routing rule"),
|
|
169
|
+
resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,
|
|
170
|
+
resourceId: snapshot.id,
|
|
171
|
+
tenantId: snapshot.tenantId,
|
|
172
|
+
organizationId: snapshot.organizationId,
|
|
173
|
+
snapshotAfter: snapshot,
|
|
174
|
+
payload: { undo: { after: snapshot } }
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
undo: async ({ logEntry, ctx }) => {
|
|
178
|
+
const after = extractUndoPayload(logEntry)?.after;
|
|
179
|
+
if (!after) return;
|
|
180
|
+
const em = ctx.container.resolve("em").fork();
|
|
181
|
+
const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)));
|
|
182
|
+
if (!rule) return;
|
|
183
|
+
await withAtomicFlush(em, [() => {
|
|
184
|
+
rule.deletedAt = /* @__PURE__ */ new Date();
|
|
185
|
+
rule.updatedAt = /* @__PURE__ */ new Date();
|
|
186
|
+
}], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.create}.undo` });
|
|
187
|
+
await emitCrudUndoSideEffects({
|
|
188
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
189
|
+
action: "deleted",
|
|
190
|
+
entity: rule,
|
|
191
|
+
identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },
|
|
192
|
+
indexer: routingRuleIndexer
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const updateRoutingRuleCommand = {
|
|
197
|
+
id: staffSupportRoutingRuleCommandIds.update,
|
|
198
|
+
async prepare(rawInput, ctx) {
|
|
199
|
+
const parsed = staffSupportRoutingRuleUpdateSchema.safeParse(rawInput);
|
|
200
|
+
if (!parsed.success) return {};
|
|
201
|
+
const em = ctx.container.resolve("em");
|
|
202
|
+
const before = await loadSnapshot(em, parsed.data.id, staffSnapshotScopeFromContext(ctx));
|
|
203
|
+
return before ? { before: { snapshot: before } } : {};
|
|
204
|
+
},
|
|
205
|
+
async execute(rawInput, ctx) {
|
|
206
|
+
const parsed = staffSupportRoutingRuleUpdateSchema.parse(rawInput);
|
|
207
|
+
const { translate } = await resolveTranslations();
|
|
208
|
+
const em = ctx.container.resolve("em").fork();
|
|
209
|
+
const scope = commandActorScope(ctx);
|
|
210
|
+
const rule = await em.findOne(
|
|
211
|
+
StaffSupportRoutingRule,
|
|
212
|
+
applyScopeToWhere({ id: parsed.id, deletedAt: null }, scope)
|
|
213
|
+
);
|
|
214
|
+
if (!rule) throw notFoundError(translate);
|
|
215
|
+
ensureTenantScope(ctx, rule.tenantId);
|
|
216
|
+
ensureOrganizationScope(ctx, rule.organizationId);
|
|
217
|
+
const isFallback = (rule.categoryValue ?? null) === null;
|
|
218
|
+
if (isFallback && parsed.isActive === false) throw fallbackRequiredError(translate);
|
|
219
|
+
const target = { tenantId: rule.tenantId, organizationId: rule.organizationId };
|
|
220
|
+
await withAtomicFlush(
|
|
221
|
+
em,
|
|
222
|
+
[
|
|
223
|
+
async () => {
|
|
224
|
+
if (parsed.timeProjectId !== void 0) {
|
|
225
|
+
await requireRoutableProject(em, parsed.timeProjectId, target, translate, {
|
|
226
|
+
requireDefaultStatus: parsed.timeProjectId !== rule.timeProjectId
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const locked = await em.findOne(
|
|
230
|
+
StaffSupportRoutingRule,
|
|
231
|
+
{ id: rule.id, ...target, deletedAt: null },
|
|
232
|
+
{ lockMode: LockMode.PESSIMISTIC_WRITE, refresh: true }
|
|
233
|
+
);
|
|
234
|
+
if (!locked) throw notFoundError(translate);
|
|
235
|
+
},
|
|
236
|
+
() => {
|
|
237
|
+
if (parsed.timeProjectId !== void 0) rule.timeProjectId = parsed.timeProjectId;
|
|
238
|
+
if (parsed.isActive !== void 0 && !isFallback) rule.isActive = parsed.isActive;
|
|
239
|
+
rule.updatedAt = /* @__PURE__ */ new Date();
|
|
240
|
+
}
|
|
241
|
+
],
|
|
242
|
+
{ transaction: true, label: staffSupportRoutingRuleCommandIds.update }
|
|
243
|
+
);
|
|
244
|
+
await emitRuleSideEffects(ctx, "updated", rule);
|
|
245
|
+
return { ruleId: rule.id };
|
|
246
|
+
},
|
|
247
|
+
buildLog: async ({ snapshots, ctx }) => {
|
|
248
|
+
const before = snapshots.before?.snapshot;
|
|
249
|
+
if (!before) return null;
|
|
250
|
+
const em = ctx.container.resolve("em").fork();
|
|
251
|
+
const after = await loadSnapshot(em, before.id, staffSnapshotScopeFromSnapshot(before));
|
|
252
|
+
if (!after) return null;
|
|
253
|
+
const { translate } = await resolveTranslations();
|
|
254
|
+
return {
|
|
255
|
+
actionLabel: translate("staff.audit.support.routingRules.update", "Update support routing rule"),
|
|
256
|
+
resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,
|
|
257
|
+
resourceId: before.id,
|
|
258
|
+
tenantId: before.tenantId,
|
|
259
|
+
organizationId: before.organizationId,
|
|
260
|
+
snapshotBefore: before,
|
|
261
|
+
snapshotAfter: after,
|
|
262
|
+
changes: buildChanges(
|
|
263
|
+
before,
|
|
264
|
+
after,
|
|
265
|
+
["timeProjectId", "isActive"]
|
|
266
|
+
),
|
|
267
|
+
payload: { undo: { before, after } }
|
|
268
|
+
};
|
|
269
|
+
},
|
|
270
|
+
undo: async ({ logEntry, ctx }) => {
|
|
271
|
+
const before = extractUndoPayload(logEntry)?.before;
|
|
272
|
+
if (!before) return;
|
|
273
|
+
const em = ctx.container.resolve("em").fork();
|
|
274
|
+
const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)));
|
|
275
|
+
if (!rule) return;
|
|
276
|
+
const { translate } = await resolveTranslations();
|
|
277
|
+
const target = { tenantId: rule.tenantId, organizationId: rule.organizationId };
|
|
278
|
+
await withAtomicFlush(em, [async () => {
|
|
279
|
+
await requireRoutableProject(em, before.timeProjectId, target, translate, {
|
|
280
|
+
requireDefaultStatus: before.timeProjectId !== rule.timeProjectId
|
|
281
|
+
});
|
|
282
|
+
const locked = await em.findOne(
|
|
283
|
+
StaffSupportRoutingRule,
|
|
284
|
+
{ id: rule.id, ...target, deletedAt: null },
|
|
285
|
+
{ lockMode: LockMode.PESSIMISTIC_WRITE, refresh: true }
|
|
286
|
+
);
|
|
287
|
+
if (!locked) throw notFoundError(translate);
|
|
288
|
+
}, () => {
|
|
289
|
+
rule.timeProjectId = before.timeProjectId;
|
|
290
|
+
rule.isActive = before.isActive;
|
|
291
|
+
rule.updatedAt = /* @__PURE__ */ new Date();
|
|
292
|
+
}], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.update}.undo` });
|
|
293
|
+
await emitCrudUndoSideEffects({
|
|
294
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
295
|
+
action: "updated",
|
|
296
|
+
entity: rule,
|
|
297
|
+
identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },
|
|
298
|
+
indexer: routingRuleIndexer
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
const deleteRoutingRuleCommand = {
|
|
303
|
+
id: staffSupportRoutingRuleCommandIds.delete,
|
|
304
|
+
async prepare(rawInput, ctx) {
|
|
305
|
+
if (!rawInput?.id) return {};
|
|
306
|
+
const em = ctx.container.resolve("em");
|
|
307
|
+
const before = await loadSnapshot(em, rawInput.id, staffSnapshotScopeFromContext(ctx));
|
|
308
|
+
return before ? { before: { snapshot: before } } : {};
|
|
309
|
+
},
|
|
310
|
+
async execute(rawInput, ctx) {
|
|
311
|
+
const { translate } = await resolveTranslations();
|
|
312
|
+
if (!rawInput?.id) throw notFoundError(translate);
|
|
313
|
+
const em = ctx.container.resolve("em").fork();
|
|
314
|
+
const scope = commandActorScope(ctx);
|
|
315
|
+
const rule = await em.findOne(
|
|
316
|
+
StaffSupportRoutingRule,
|
|
317
|
+
applyScopeToWhere({ id: rawInput.id, deletedAt: null }, scope)
|
|
318
|
+
);
|
|
319
|
+
if (!rule) throw notFoundError(translate);
|
|
320
|
+
ensureTenantScope(ctx, rule.tenantId);
|
|
321
|
+
ensureOrganizationScope(ctx, rule.organizationId);
|
|
322
|
+
if ((rule.categoryValue ?? null) === null) throw fallbackRequiredError(translate);
|
|
323
|
+
await withAtomicFlush(em, [() => {
|
|
324
|
+
rule.deletedAt = /* @__PURE__ */ new Date();
|
|
325
|
+
rule.updatedAt = /* @__PURE__ */ new Date();
|
|
326
|
+
}], { transaction: true, label: staffSupportRoutingRuleCommandIds.delete });
|
|
327
|
+
await emitRuleSideEffects(ctx, "deleted", rule);
|
|
328
|
+
return { ruleId: rule.id };
|
|
329
|
+
},
|
|
330
|
+
buildLog: async ({ snapshots }) => {
|
|
331
|
+
const before = snapshots.before?.snapshot;
|
|
332
|
+
if (!before) return null;
|
|
333
|
+
const { translate } = await resolveTranslations();
|
|
334
|
+
return {
|
|
335
|
+
actionLabel: translate("staff.audit.support.routingRules.delete", "Delete support routing rule"),
|
|
336
|
+
resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,
|
|
337
|
+
resourceId: before.id,
|
|
338
|
+
tenantId: before.tenantId,
|
|
339
|
+
organizationId: before.organizationId,
|
|
340
|
+
snapshotBefore: before,
|
|
341
|
+
payload: { undo: { before } }
|
|
342
|
+
};
|
|
343
|
+
},
|
|
344
|
+
undo: async ({ logEntry, ctx }) => {
|
|
345
|
+
const before = extractUndoPayload(logEntry)?.before;
|
|
346
|
+
if (!before) return;
|
|
347
|
+
const em = ctx.container.resolve("em").fork();
|
|
348
|
+
const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)));
|
|
349
|
+
if (!rule || !rule.deletedAt) return;
|
|
350
|
+
const { translate } = await resolveTranslations();
|
|
351
|
+
const categoryValue = rule.categoryValue ?? null;
|
|
352
|
+
const isFallback = categoryValue === null;
|
|
353
|
+
try {
|
|
354
|
+
await withAtomicFlush(em, [
|
|
355
|
+
async () => {
|
|
356
|
+
await requireRoutableProject(em, rule.timeProjectId, { tenantId: rule.tenantId, organizationId: rule.organizationId }, translate);
|
|
357
|
+
const newer = await em.findOne(
|
|
358
|
+
StaffSupportRoutingRule,
|
|
359
|
+
{
|
|
360
|
+
tenantId: rule.tenantId,
|
|
361
|
+
organizationId: rule.organizationId,
|
|
362
|
+
categoryValue,
|
|
363
|
+
deletedAt: null,
|
|
364
|
+
id: { $ne: rule.id }
|
|
365
|
+
},
|
|
366
|
+
{ fields: ["id"] }
|
|
367
|
+
);
|
|
368
|
+
if (newer) throw duplicateRuleError(translate, isFallback);
|
|
369
|
+
},
|
|
370
|
+
() => {
|
|
371
|
+
rule.deletedAt = null;
|
|
372
|
+
rule.updatedAt = /* @__PURE__ */ new Date();
|
|
373
|
+
}
|
|
374
|
+
], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.delete}.undo` });
|
|
375
|
+
} catch (err) {
|
|
376
|
+
if (isUniqueViolation(err)) throw duplicateRuleError(translate, isFallback);
|
|
377
|
+
throw err;
|
|
378
|
+
}
|
|
379
|
+
await emitCrudUndoSideEffects({
|
|
380
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
381
|
+
action: "created",
|
|
382
|
+
entity: rule,
|
|
383
|
+
identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },
|
|
384
|
+
indexer: routingRuleIndexer
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
async function emitProjectSideEffects(ctx, action, project, undo) {
|
|
389
|
+
const params = {
|
|
390
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
391
|
+
action,
|
|
392
|
+
entity: project,
|
|
393
|
+
identifiers: { id: project.id, organizationId: project.organizationId, tenantId: project.tenantId },
|
|
394
|
+
events: staffTimeProjectCrudEvents,
|
|
395
|
+
indexer: staffTimeProjectCrudIndexer
|
|
396
|
+
};
|
|
397
|
+
if (undo) await emitCrudUndoSideEffects(params);
|
|
398
|
+
else await emitCrudSideEffects(params);
|
|
399
|
+
}
|
|
400
|
+
const createFallbackProjectCommand = {
|
|
401
|
+
id: staffSupportRoutingRuleCommandIds.createFallbackProject,
|
|
402
|
+
async execute(rawInput, ctx) {
|
|
403
|
+
const parsed = staffSupportFallbackProjectCreateSchema.parse(rawInput);
|
|
404
|
+
commandInputScope(ctx, parsed.tenantId, parsed.organizationId);
|
|
405
|
+
const { translate } = await resolveTranslations();
|
|
406
|
+
const target = { tenantId: parsed.tenantId, organizationId: parsed.organizationId };
|
|
407
|
+
const em = ctx.container.resolve("em").fork();
|
|
408
|
+
const result = await ensureFallbackProjectAndRule(em, target, {
|
|
409
|
+
translate,
|
|
410
|
+
generateCode: resolveContainerProjectCodeGenerator(ctx.container),
|
|
411
|
+
projectName: translate("staff.support.fallbackProject.name", "Customer support")
|
|
412
|
+
});
|
|
413
|
+
if (result.created) {
|
|
414
|
+
const project = await em.findOne(StaffTimeProject, { id: result.timeProjectId, ...target });
|
|
415
|
+
if (project) await emitProjectSideEffects(ctx, "created", project, false);
|
|
416
|
+
const rule = await em.findOne(StaffSupportRoutingRule, { id: result.ruleId, ...target });
|
|
417
|
+
if (rule) await emitRuleSideEffects(ctx, "created", rule);
|
|
418
|
+
}
|
|
419
|
+
return { ...result, ...target };
|
|
420
|
+
},
|
|
421
|
+
buildLog: async ({ result }) => {
|
|
422
|
+
if (!result.created) return null;
|
|
423
|
+
const { translate } = await resolveTranslations();
|
|
424
|
+
return {
|
|
425
|
+
actionLabel: translate("staff.audit.support.routingRules.createFallbackProject", "Create support fallback project"),
|
|
426
|
+
resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,
|
|
427
|
+
resourceId: result.ruleId,
|
|
428
|
+
tenantId: result.tenantId,
|
|
429
|
+
organizationId: result.organizationId,
|
|
430
|
+
context: { cacheAliases: [`${staffTimeProjectCrudEvents.module}.${staffTimeProjectCrudEvents.entity}`] },
|
|
431
|
+
payload: {
|
|
432
|
+
undo: {
|
|
433
|
+
ruleId: result.ruleId,
|
|
434
|
+
timeProjectId: result.timeProjectId,
|
|
435
|
+
taskStatusIds: result.taskStatusIds,
|
|
436
|
+
tenantId: result.tenantId,
|
|
437
|
+
organizationId: result.organizationId
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
},
|
|
442
|
+
undo: async ({ logEntry, ctx }) => {
|
|
443
|
+
const payload = extractUndoPayload(logEntry);
|
|
444
|
+
if (!payload?.ruleId || !payload.timeProjectId) return;
|
|
445
|
+
const where = { tenantId: payload.tenantId, organizationId: payload.organizationId };
|
|
446
|
+
const em = ctx.container.resolve("em").fork();
|
|
447
|
+
const statusIds = Array.isArray(payload.taskStatusIds) ? payload.taskStatusIds : [];
|
|
448
|
+
const removal = { project: null, rule: null, statuses: [] };
|
|
449
|
+
await withAtomicFlush(em, [async () => {
|
|
450
|
+
removal.project = await em.findOne(
|
|
451
|
+
StaffTimeProject,
|
|
452
|
+
{ id: payload.timeProjectId, ...where, deletedAt: null },
|
|
453
|
+
{ lockMode: LockMode.PESSIMISTIC_WRITE }
|
|
454
|
+
);
|
|
455
|
+
const liveTaskCount = await em.count(StaffTimeTask, { timeProjectId: payload.timeProjectId, ...where, deletedAt: null });
|
|
456
|
+
if (liveTaskCount > 0) {
|
|
457
|
+
const { translate } = await resolveTranslations();
|
|
458
|
+
throw new CrudHttpError(409, {
|
|
459
|
+
code: "support_fallback_project_in_use",
|
|
460
|
+
error: translate(
|
|
461
|
+
"staff.support.errors.fallbackProjectInUse",
|
|
462
|
+
"The support project already has tasks, so creating it cannot be undone. Point the fallback rule at another project instead."
|
|
463
|
+
)
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
removal.statuses = statusIds.length > 0 ? await em.find(StaffTimeTaskStatus, { id: { $in: statusIds }, timeProjectId: payload.timeProjectId, ...where, deletedAt: null }) : [];
|
|
467
|
+
}, async () => {
|
|
468
|
+
const now = /* @__PURE__ */ new Date();
|
|
469
|
+
const removedRuleCount = await em.nativeUpdate(
|
|
470
|
+
StaffSupportRoutingRule,
|
|
471
|
+
{ id: payload.ruleId, ...where, timeProjectId: payload.timeProjectId, deletedAt: null },
|
|
472
|
+
{ deletedAt: now, updatedAt: now }
|
|
473
|
+
);
|
|
474
|
+
removal.rule = removedRuleCount > 0 ? await em.findOne(StaffSupportRoutingRule, { id: payload.ruleId, ...where }, { refresh: true }) : null;
|
|
475
|
+
if (removal.project) {
|
|
476
|
+
removal.project.deletedAt = now;
|
|
477
|
+
removal.project.updatedAt = now;
|
|
478
|
+
}
|
|
479
|
+
for (const status of removal.statuses) {
|
|
480
|
+
status.deletedAt = now;
|
|
481
|
+
status.updatedAt = now;
|
|
482
|
+
}
|
|
483
|
+
}], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.createFallbackProject}.undo` });
|
|
484
|
+
const { project, rule: ruleToRemove } = removal;
|
|
485
|
+
if (ruleToRemove) {
|
|
486
|
+
await emitCrudUndoSideEffects({
|
|
487
|
+
dataEngine: ctx.container.resolve("dataEngine"),
|
|
488
|
+
action: "deleted",
|
|
489
|
+
entity: ruleToRemove,
|
|
490
|
+
identifiers: { id: ruleToRemove.id, organizationId: ruleToRemove.organizationId, tenantId: ruleToRemove.tenantId },
|
|
491
|
+
indexer: routingRuleIndexer
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
if (project) await emitProjectSideEffects(ctx, "deleted", project, true);
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
registerCommand(createRoutingRuleCommand);
|
|
498
|
+
registerCommand(updateRoutingRuleCommand);
|
|
499
|
+
registerCommand(deleteRoutingRuleCommand);
|
|
500
|
+
registerCommand(createFallbackProjectCommand);
|
|
501
|
+
export {
|
|
502
|
+
SUPPORT_ROUTING_RULE_RESOURCE_KIND,
|
|
503
|
+
staffSupportRoutingRuleCommandIds
|
|
504
|
+
};
|
|
505
|
+
//# sourceMappingURL=support-routing-rules.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/staff/commands/support-routing-rules.ts"],
|
|
4
|
+
"sourcesContent": ["import type { EntityManager } from '@mikro-orm/postgresql'\nimport { LockMode } from '@mikro-orm/core'\nimport type { CommandHandler, CommandRuntimeContext } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport { CrudHttpError, isUniqueViolation } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { withAtomicFlush } from '@open-mercato/shared/lib/commands/flush'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport { StaffSupportRoutingRule, StaffTimeProject, StaffTimeTask, StaffTimeTaskStatus } from '../data/entities'\nimport { staffTimeProjectCrudEvents, staffTimeProjectCrudIndexer } from '../lib/crud'\nimport {\n staffSupportFallbackProjectCreateSchema,\n staffSupportRoutingRuleCreateSchema,\n staffSupportRoutingRuleUpdateSchema,\n type StaffSupportFallbackProjectCreateInput,\n type StaffSupportRoutingRuleCreateInput,\n type StaffSupportRoutingRuleUpdateInput,\n} from '../data/validators'\nimport { findSupportTicketCategory } from '../lib/support/dictionaries'\nimport { ensureFallbackProjectAndRule, resolveContainerProjectCodeGenerator } from '../lib/support/seedDefaults'\nimport {\n applyScopeToWhere,\n commandActorScope,\n commandInputScope,\n ensureOrganizationScope,\n ensureTenantScope,\n explicitStaffCommandScope,\n extractUndoPayload,\n lockLiveProjectForWrite,\n scopedStaffSnapshotWhere,\n staffSnapshotScopeFromContext,\n staffSnapshotScopeFromSnapshot,\n type StaffSnapshotScope,\n} from './shared'\n\nexport const staffSupportRoutingRuleCommandIds = {\n create: 'staff.support.routing_rules.create',\n update: 'staff.support.routing_rules.update',\n delete: 'staff.support.routing_rules.delete',\n createFallbackProject: 'staff.support.routing_rules.create_fallback_project',\n} as const\n\nexport const SUPPORT_ROUTING_RULE_RESOURCE_KIND = 'staff.support.routing_rule'\n\nconst routingRuleIndexer: CrudIndexerConfig<StaffSupportRoutingRule> = {\n entityType: 'staff:staff_support_routing_rule',\n}\n\ntype Translate = (key: string, fallback: string) => string\n\ntype RoutingRuleSnapshot = {\n id: string\n tenantId: string\n organizationId: string\n categoryValue: string | null\n timeProjectId: string\n isActive: boolean\n deletedAt: string | null\n}\n\ntype RoutingRuleUndoPayload = {\n before?: RoutingRuleSnapshot | null\n after?: RoutingRuleSnapshot | null\n}\n\nfunction toSnapshot(rule: StaffSupportRoutingRule): RoutingRuleSnapshot {\n return {\n id: rule.id,\n tenantId: rule.tenantId,\n organizationId: rule.organizationId,\n categoryValue: rule.categoryValue ?? null,\n timeProjectId: rule.timeProjectId,\n isActive: rule.isActive,\n deletedAt: rule.deletedAt ? rule.deletedAt.toISOString() : null,\n }\n}\n\nasync function loadSnapshot(\n em: EntityManager,\n id: string,\n scope?: StaffSnapshotScope | null,\n): Promise<RoutingRuleSnapshot | null> {\n const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(id, scope))\n return rule ? toSnapshot(rule) : null\n}\n\nfunction notFoundError(translate: Translate): CrudHttpError {\n return new CrudHttpError(404, {\n error: translate('staff.support.errors.routingRuleNotFound', 'Routing rule not found.'),\n })\n}\n\nfunction fallbackRequiredError(translate: Translate): CrudHttpError {\n return new CrudHttpError(422, {\n code: 'support_fallback_rule_required',\n error: translate(\n 'staff.support.errors.fallbackRuleRequired',\n 'The fallback rule cannot be deleted or paused. Point it at another project instead.',\n ),\n })\n}\n\nfunction duplicateRuleError(translate: Translate, isFallback: boolean): CrudHttpError {\n const message = isFallback\n ? translate('staff.support.errors.fallbackRuleExists', 'This organization already has a fallback rule.')\n : translate('staff.support.errors.categoryRuleExists', 'This category already has a routing rule.')\n return new CrudHttpError(409, {\n code: 'support_routing_rule_duplicate',\n error: message,\n fieldErrors: { categoryValue: message },\n })\n}\n\nasync function requireRoutableProject(\n em: EntityManager,\n timeProjectId: string,\n scope: { tenantId: string; organizationId: string },\n translate: Translate,\n options: { requireDefaultStatus?: boolean } = {},\n): Promise<void> {\n const project = await lockLiveProjectForWrite(em, timeProjectId, explicitStaffCommandScope(scope.tenantId, scope.organizationId))\n if (!project) {\n const message = translate('staff.support.errors.projectNotFound', 'The selected project does not exist in this organization.')\n throw new CrudHttpError(422, { code: 'support_project_not_found', error: message, fieldErrors: { timeProjectId: message } })\n }\n if (options.requireDefaultStatus === false) return\n const defaultStatus = await em.findOne(\n StaffTimeTaskStatus,\n { timeProjectId, tenantId: scope.tenantId, organizationId: scope.organizationId, isDefault: true, deletedAt: null },\n { fields: ['id'] },\n )\n if (!defaultStatus) {\n const message = translate(\n 'staff.support.errors.projectHasNoDefaultStatus',\n 'The selected project has no default task status, so tickets cannot be filed on its board.',\n )\n throw new CrudHttpError(422, { code: 'support_project_no_default_status', error: message, fieldErrors: { timeProjectId: message } })\n }\n}\n\nasync function requireKnownCategory(\n em: EntityManager,\n categoryValue: string,\n scope: { tenantId: string; organizationId: string },\n translate: Translate,\n): Promise<void> {\n const category = await findSupportTicketCategory(em, scope, categoryValue)\n if (category) return\n const message = translate('staff.support.errors.categoryNotFound', 'This category does not exist in the support categories dictionary.')\n throw new CrudHttpError(422, { code: 'support_category_not_found', error: message, fieldErrors: { categoryValue: message } })\n}\n\nasync function emitRuleSideEffects(\n ctx: CommandRuntimeContext,\n action: 'created' | 'updated' | 'deleted',\n rule: StaffSupportRoutingRule,\n): Promise<void> {\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action,\n entity: rule,\n identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },\n indexer: routingRuleIndexer,\n })\n}\n\nconst createRoutingRuleCommand: CommandHandler<StaffSupportRoutingRuleCreateInput, { ruleId: string }> = {\n id: staffSupportRoutingRuleCommandIds.create,\n async execute(rawInput, ctx) {\n const parsed = staffSupportRoutingRuleCreateSchema.parse(rawInput)\n const scope = commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n const { translate } = await resolveTranslations()\n const target = { tenantId: parsed.tenantId, organizationId: parsed.organizationId }\n const categoryValue = parsed.categoryValue ?? null\n const isFallback = categoryValue === null\n if (isFallback && parsed.isActive === false) throw fallbackRequiredError(translate)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let created: StaffSupportRoutingRule | null = null\n try {\n await withAtomicFlush(\n em,\n [\n async () => {\n await requireRoutableProject(em, parsed.timeProjectId, target, translate)\n if (categoryValue !== null) await requireKnownCategory(em, categoryValue, target, translate)\n const duplicate = await em.findOne(\n StaffSupportRoutingRule,\n applyScopeToWhere<StaffSupportRoutingRule>({ categoryValue, deletedAt: null }, scope),\n { fields: ['id'] },\n )\n if (duplicate) throw duplicateRuleError(translate, isFallback)\n },\n () => {\n created = em.create(StaffSupportRoutingRule, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n categoryValue,\n timeProjectId: parsed.timeProjectId,\n isActive: isFallback ? true : parsed.isActive ?? true,\n createdAt: new Date(),\n updatedAt: new Date(),\n deletedAt: null,\n })\n em.persist(created)\n },\n ],\n { transaction: true, label: staffSupportRoutingRuleCommandIds.create },\n )\n } catch (err) {\n if (isUniqueViolation(err)) throw duplicateRuleError(translate, isFallback)\n throw err\n }\n const record = created as StaffSupportRoutingRule | null\n if (!record) throw notFoundError(translate)\n await emitRuleSideEffects(ctx, 'created', record)\n return { ruleId: record.id }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadSnapshot(em, result.ruleId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.support.routingRules.create', 'Create support routing rule'),\n resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,\n resourceId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n snapshotAfter: snapshot,\n payload: { undo: { after: snapshot } satisfies RoutingRuleUndoPayload },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const after = extractUndoPayload<RoutingRuleUndoPayload>(logEntry)?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)))\n if (!rule) return\n await withAtomicFlush(em, [() => {\n rule.deletedAt = new Date()\n rule.updatedAt = new Date()\n }], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.create}.undo` })\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: rule,\n identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },\n indexer: routingRuleIndexer,\n })\n },\n}\n\nconst updateRoutingRuleCommand: CommandHandler<StaffSupportRoutingRuleUpdateInput, { ruleId: string }> = {\n id: staffSupportRoutingRuleCommandIds.update,\n async prepare(rawInput, ctx) {\n const parsed = staffSupportRoutingRuleUpdateSchema.safeParse(rawInput)\n if (!parsed.success) return {}\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadSnapshot(em, parsed.data.id, staffSnapshotScopeFromContext(ctx))\n return before ? { before: { snapshot: before } } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = staffSupportRoutingRuleUpdateSchema.parse(rawInput)\n const { translate } = await resolveTranslations()\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const rule = await em.findOne(\n StaffSupportRoutingRule,\n applyScopeToWhere<StaffSupportRoutingRule>({ id: parsed.id, deletedAt: null }, scope),\n )\n if (!rule) throw notFoundError(translate)\n ensureTenantScope(ctx, rule.tenantId)\n ensureOrganizationScope(ctx, rule.organizationId)\n const isFallback = (rule.categoryValue ?? null) === null\n if (isFallback && parsed.isActive === false) throw fallbackRequiredError(translate)\n const target = { tenantId: rule.tenantId, organizationId: rule.organizationId }\n\n await withAtomicFlush(\n em,\n [\n async () => {\n if (parsed.timeProjectId !== undefined) {\n await requireRoutableProject(em, parsed.timeProjectId, target, translate, {\n requireDefaultStatus: parsed.timeProjectId !== rule.timeProjectId,\n })\n }\n const locked = await em.findOne(\n StaffSupportRoutingRule,\n { id: rule.id, ...target, deletedAt: null },\n { lockMode: LockMode.PESSIMISTIC_WRITE, refresh: true },\n )\n if (!locked) throw notFoundError(translate)\n },\n () => {\n if (parsed.timeProjectId !== undefined) rule.timeProjectId = parsed.timeProjectId\n if (parsed.isActive !== undefined && !isFallback) rule.isActive = parsed.isActive\n rule.updatedAt = new Date()\n },\n ],\n { transaction: true, label: staffSupportRoutingRuleCommandIds.update },\n )\n await emitRuleSideEffects(ctx, 'updated', rule)\n return { ruleId: rule.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const before = (snapshots.before as { snapshot?: RoutingRuleSnapshot } | undefined)?.snapshot\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const after = await loadSnapshot(em, before.id, staffSnapshotScopeFromSnapshot(before))\n if (!after) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.support.routingRules.update', 'Update support routing rule'),\n resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n changes: buildChanges(\n before as unknown as Record<string, unknown>,\n after as unknown as Record<string, unknown>,\n ['timeProjectId', 'isActive'],\n ),\n payload: { undo: { before, after } satisfies RoutingRuleUndoPayload },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<RoutingRuleUndoPayload>(logEntry)?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!rule) return\n const { translate } = await resolveTranslations()\n const target = { tenantId: rule.tenantId, organizationId: rule.organizationId }\n await withAtomicFlush(em, [async () => {\n await requireRoutableProject(em, before.timeProjectId, target, translate, {\n requireDefaultStatus: before.timeProjectId !== rule.timeProjectId,\n })\n const locked = await em.findOne(\n StaffSupportRoutingRule,\n { id: rule.id, ...target, deletedAt: null },\n { lockMode: LockMode.PESSIMISTIC_WRITE, refresh: true },\n )\n if (!locked) throw notFoundError(translate)\n }, () => {\n rule.timeProjectId = before.timeProjectId\n rule.isActive = before.isActive\n rule.updatedAt = new Date()\n }], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.update}.undo` })\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'updated',\n entity: rule,\n identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },\n indexer: routingRuleIndexer,\n })\n },\n}\n\nconst deleteRoutingRuleCommand: CommandHandler<{ id?: string }, { ruleId: string }> = {\n id: staffSupportRoutingRuleCommandIds.delete,\n async prepare(rawInput, ctx) {\n if (!rawInput?.id) return {}\n const em = ctx.container.resolve('em') as EntityManager\n const before = await loadSnapshot(em, rawInput.id, staffSnapshotScopeFromContext(ctx))\n return before ? { before: { snapshot: before } } : {}\n },\n async execute(rawInput, ctx) {\n const { translate } = await resolveTranslations()\n if (!rawInput?.id) throw notFoundError(translate)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const rule = await em.findOne(\n StaffSupportRoutingRule,\n applyScopeToWhere<StaffSupportRoutingRule>({ id: rawInput.id, deletedAt: null }, scope),\n )\n if (!rule) throw notFoundError(translate)\n ensureTenantScope(ctx, rule.tenantId)\n ensureOrganizationScope(ctx, rule.organizationId)\n if ((rule.categoryValue ?? null) === null) throw fallbackRequiredError(translate)\n await withAtomicFlush(em, [() => {\n rule.deletedAt = new Date()\n rule.updatedAt = new Date()\n }], { transaction: true, label: staffSupportRoutingRuleCommandIds.delete })\n await emitRuleSideEffects(ctx, 'deleted', rule)\n return { ruleId: rule.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = (snapshots.before as { snapshot?: RoutingRuleSnapshot } | undefined)?.snapshot\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.support.routingRules.delete', 'Delete support routing rule'),\n resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: { undo: { before } satisfies RoutingRuleUndoPayload },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const before = extractUndoPayload<RoutingRuleUndoPayload>(logEntry)?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const rule = await em.findOne(StaffSupportRoutingRule, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!rule || !rule.deletedAt) return\n const { translate } = await resolveTranslations()\n const categoryValue = rule.categoryValue ?? null\n const isFallback = categoryValue === null\n try {\n await withAtomicFlush(em, [\n async () => {\n await requireRoutableProject(em, rule.timeProjectId, { tenantId: rule.tenantId, organizationId: rule.organizationId }, translate)\n const newer = await em.findOne(\n StaffSupportRoutingRule,\n {\n tenantId: rule.tenantId,\n organizationId: rule.organizationId,\n categoryValue,\n deletedAt: null,\n id: { $ne: rule.id },\n },\n { fields: ['id'] },\n )\n if (newer) throw duplicateRuleError(translate, isFallback)\n },\n () => {\n rule.deletedAt = null\n rule.updatedAt = new Date()\n },\n ], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.delete}.undo` })\n } catch (err) {\n if (isUniqueViolation(err)) throw duplicateRuleError(translate, isFallback)\n throw err\n }\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: rule,\n identifiers: { id: rule.id, organizationId: rule.organizationId, tenantId: rule.tenantId },\n indexer: routingRuleIndexer,\n })\n },\n}\n\nexport type SupportFallbackProjectResult = {\n ruleId: string\n timeProjectId: string\n created: boolean\n taskStatusIds: string[]\n tenantId: string\n organizationId: string\n}\n\ntype FallbackProjectUndoPayload = {\n ruleId: string\n timeProjectId: string\n taskStatusIds: string[]\n tenantId: string\n organizationId: string\n}\n\nasync function emitProjectSideEffects(\n ctx: CommandRuntimeContext,\n action: 'created' | 'deleted',\n project: StaffTimeProject,\n undo: boolean,\n): Promise<void> {\n const params = {\n dataEngine: ctx.container.resolve('dataEngine') as DataEngine,\n action,\n entity: project,\n identifiers: { id: project.id, organizationId: project.organizationId, tenantId: project.tenantId },\n events: staffTimeProjectCrudEvents,\n indexer: staffTimeProjectCrudIndexer,\n }\n if (undo) await emitCrudUndoSideEffects(params)\n else await emitCrudSideEffects(params)\n}\n\nconst createFallbackProjectCommand: CommandHandler<StaffSupportFallbackProjectCreateInput, SupportFallbackProjectResult> = {\n id: staffSupportRoutingRuleCommandIds.createFallbackProject,\n async execute(rawInput, ctx) {\n const parsed = staffSupportFallbackProjectCreateSchema.parse(rawInput)\n commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n const { translate } = await resolveTranslations()\n const target = { tenantId: parsed.tenantId, organizationId: parsed.organizationId }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const result = await ensureFallbackProjectAndRule(em, target, {\n translate,\n generateCode: resolveContainerProjectCodeGenerator(ctx.container),\n projectName: translate('staff.support.fallbackProject.name', 'Customer support'),\n })\n if (result.created) {\n const project = await em.findOne(StaffTimeProject, { id: result.timeProjectId, ...target })\n if (project) await emitProjectSideEffects(ctx, 'created', project, false)\n const rule = await em.findOne(StaffSupportRoutingRule, { id: result.ruleId, ...target })\n if (rule) await emitRuleSideEffects(ctx, 'created', rule)\n }\n return { ...result, ...target }\n },\n buildLog: async ({ result }) => {\n if (!result.created) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.support.routingRules.createFallbackProject', 'Create support fallback project'),\n resourceKind: SUPPORT_ROUTING_RULE_RESOURCE_KIND,\n resourceId: result.ruleId,\n tenantId: result.tenantId,\n organizationId: result.organizationId,\n context: { cacheAliases: [`${staffTimeProjectCrudEvents.module}.${staffTimeProjectCrudEvents.entity}`] },\n payload: {\n undo: {\n ruleId: result.ruleId,\n timeProjectId: result.timeProjectId,\n taskStatusIds: result.taskStatusIds,\n tenantId: result.tenantId,\n organizationId: result.organizationId,\n } satisfies FallbackProjectUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<FallbackProjectUndoPayload>(logEntry)\n if (!payload?.ruleId || !payload.timeProjectId) return\n const where = { tenantId: payload.tenantId, organizationId: payload.organizationId }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const statusIds = Array.isArray(payload.taskStatusIds) ? payload.taskStatusIds : []\n const removal: {\n project: StaffTimeProject | null\n rule: StaffSupportRoutingRule | null\n statuses: StaffTimeTaskStatus[]\n } = { project: null, rule: null, statuses: [] }\n await withAtomicFlush(em, [async () => {\n removal.project = await em.findOne(\n StaffTimeProject,\n { id: payload.timeProjectId, ...where, deletedAt: null },\n { lockMode: LockMode.PESSIMISTIC_WRITE },\n )\n const liveTaskCount = await em.count(StaffTimeTask, { timeProjectId: payload.timeProjectId, ...where, deletedAt: null })\n if (liveTaskCount > 0) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(409, {\n code: 'support_fallback_project_in_use',\n error: translate(\n 'staff.support.errors.fallbackProjectInUse',\n 'The support project already has tasks, so creating it cannot be undone. Point the fallback rule at another project instead.',\n ),\n })\n }\n removal.statuses = statusIds.length > 0\n ? await em.find(StaffTimeTaskStatus, { id: { $in: statusIds }, timeProjectId: payload.timeProjectId, ...where, deletedAt: null })\n : []\n }, async () => {\n const now = new Date()\n const removedRuleCount = await em.nativeUpdate(\n StaffSupportRoutingRule,\n { id: payload.ruleId, ...where, timeProjectId: payload.timeProjectId, deletedAt: null },\n { deletedAt: now, updatedAt: now },\n )\n removal.rule = removedRuleCount > 0\n ? await em.findOne(StaffSupportRoutingRule, { id: payload.ruleId, ...where }, { refresh: true })\n : null\n if (removal.project) {\n removal.project.deletedAt = now\n removal.project.updatedAt = now\n }\n for (const status of removal.statuses) {\n status.deletedAt = now\n status.updatedAt = now\n }\n }], { transaction: true, label: `${staffSupportRoutingRuleCommandIds.createFallbackProject}.undo` })\n const { project, rule: ruleToRemove } = removal\n if (ruleToRemove) {\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: ruleToRemove,\n identifiers: { id: ruleToRemove.id, organizationId: ruleToRemove.organizationId, tenantId: ruleToRemove.tenantId },\n indexer: routingRuleIndexer,\n })\n }\n if (project) await emitProjectSideEffects(ctx, 'deleted', project, true)\n },\n}\n\nregisterCommand(createRoutingRuleCommand)\nregisterCommand(updateRoutingRuleCommand)\nregisterCommand(deleteRoutingRuleCommand)\nregisterCommand(createFallbackProjectCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|