@open-mercato/core 0.4.5-develop-5191db4ef3 → 0.4.5-develop-033a719bf2
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/dist/generated/entities/message/index.js +65 -0
- package/dist/generated/entities/message/index.js.map +7 -0
- package/dist/generated/entities/message_access_token/index.js +19 -0
- package/dist/generated/entities/message_access_token/index.js.map +7 -0
- package/dist/generated/entities/message_confirmation/index.js +21 -0
- package/dist/generated/entities/message_confirmation/index.js.map +7 -0
- package/dist/generated/entities/message_object/index.js +23 -0
- package/dist/generated/entities/message_object/index.js.map +7 -0
- package/dist/generated/entities/message_recipient/index.js +31 -0
- package/dist/generated/entities/message_recipient/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +8 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +10 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +27 -8
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/lib/messageObjectPreviews.js +131 -0
- package/dist/modules/customers/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/customers/message-objects.js +71 -0
- package/dist/modules/customers/message-objects.js.map +7 -0
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +51 -0
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +7 -0
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +35 -0
- package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +7 -0
- package/dist/modules/customers/widgets/messages/index.js +7 -0
- package/dist/modules/customers/widgets/messages/index.js.map +7 -0
- package/dist/modules/messages/acl.js +15 -0
- package/dist/modules/messages/acl.js.map +7 -0
- package/dist/modules/messages/api/[id]/actions/[actionId]/route.js +92 -0
- package/dist/modules/messages/api/[id]/actions/[actionId]/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/archive/route.js +120 -0
- package/dist/modules/messages/api/[id]/archive/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/attachments/route.js +195 -0
- package/dist/modules/messages/api/[id]/attachments/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/confirmation/route.js +67 -0
- package/dist/modules/messages/api/[id]/confirmation/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/conversation/archive/route.js +68 -0
- package/dist/modules/messages/api/[id]/conversation/archive/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/conversation/read/route.js +68 -0
- package/dist/modules/messages/api/[id]/conversation/read/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/conversation/route.js +68 -0
- package/dist/modules/messages/api/[id]/conversation/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/forward/route.js +85 -0
- package/dist/modules/messages/api/[id]/forward/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/forward-preview/route.js +70 -0
- package/dist/modules/messages/api/[id]/forward-preview/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/read/route.js +120 -0
- package/dist/modules/messages/api/[id]/read/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/reply/route.js +87 -0
- package/dist/modules/messages/api/[id]/reply/route.js.map +7 -0
- package/dist/modules/messages/api/[id]/route.js +350 -0
- package/dist/modules/messages/api/[id]/route.js.map +7 -0
- package/dist/modules/messages/api/object-types/route.js +54 -0
- package/dist/modules/messages/api/object-types/route.js.map +7 -0
- package/dist/modules/messages/api/openapi.js +261 -0
- package/dist/modules/messages/api/openapi.js.map +7 -0
- package/dist/modules/messages/api/route.js +262 -0
- package/dist/modules/messages/api/route.js.map +7 -0
- package/dist/modules/messages/api/token/[token]/route.js +99 -0
- package/dist/modules/messages/api/token/[token]/route.js.map +7 -0
- package/dist/modules/messages/api/types/route.js +40 -0
- package/dist/modules/messages/api/types/route.js.map +7 -0
- package/dist/modules/messages/api/unread-count/route.js +43 -0
- package/dist/modules/messages/api/unread-count/route.js.map +7 -0
- package/dist/modules/messages/backend/messages/[id]/page.js +10 -0
- package/dist/modules/messages/backend/messages/[id]/page.js.map +7 -0
- package/dist/modules/messages/backend/messages/[id]/page.meta.js +16 -0
- package/dist/modules/messages/backend/messages/[id]/page.meta.js.map +7 -0
- package/dist/modules/messages/backend/messages/compose/page.js +10 -0
- package/dist/modules/messages/backend/messages/compose/page.js.map +7 -0
- package/dist/modules/messages/backend/messages/compose/page.meta.js +17 -0
- package/dist/modules/messages/backend/messages/compose/page.meta.js.map +7 -0
- package/dist/modules/messages/backend/page.js +10 -0
- package/dist/modules/messages/backend/page.js.map +7 -0
- package/dist/modules/messages/backend/page.meta.js +33 -0
- package/dist/modules/messages/backend/page.meta.js.map +7 -0
- package/dist/modules/messages/commands/actions.js +265 -0
- package/dist/modules/messages/commands/actions.js.map +7 -0
- package/dist/modules/messages/commands/attachments.js +217 -0
- package/dist/modules/messages/commands/attachments.js.map +7 -0
- package/dist/modules/messages/commands/confirmations.js +151 -0
- package/dist/modules/messages/commands/confirmations.js.map +7 -0
- package/dist/modules/messages/commands/conversation.js +240 -0
- package/dist/modules/messages/commands/conversation.js.map +7 -0
- package/dist/modules/messages/commands/messages.js +748 -0
- package/dist/modules/messages/commands/messages.js.map +7 -0
- package/dist/modules/messages/commands/recipients.js +259 -0
- package/dist/modules/messages/commands/recipients.js.map +7 -0
- package/dist/modules/messages/commands/shared.js +258 -0
- package/dist/modules/messages/commands/shared.js.map +7 -0
- package/dist/modules/messages/commands/tokens.js +69 -0
- package/dist/modules/messages/commands/tokens.js.map +7 -0
- package/dist/modules/messages/components/ComposeMessagePageClient.js +24 -0
- package/dist/modules/messages/components/ComposeMessagePageClient.js.map +7 -0
- package/dist/modules/messages/components/MessageDetailPageClient.js +261 -0
- package/dist/modules/messages/components/MessageDetailPageClient.js.map +7 -0
- package/dist/modules/messages/components/MessagesInboxPageClient.js +390 -0
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +7 -0
- package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js +31 -0
- package/dist/modules/messages/components/confirmation/MessageConfirmationActions.js.map +7 -0
- package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js +69 -0
- package/dist/modules/messages/components/confirmation/MessageConfirmationContent.js.map +7 -0
- package/dist/modules/messages/components/defaults/DefaultMessageActions.js +31 -0
- package/dist/modules/messages/components/defaults/DefaultMessageActions.js.map +7 -0
- package/dist/modules/messages/components/defaults/DefaultMessageContent.js +19 -0
- package/dist/modules/messages/components/defaults/DefaultMessageContent.js.map +7 -0
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +90 -0
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.js.map +7 -0
- package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js +86 -0
- package/dist/modules/messages/components/defaults/MessageRecordObjectDetail.js.map +7 -0
- package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js +61 -0
- package/dist/modules/messages/components/defaults/MessageRecordObjectPreview.js.map +7 -0
- package/dist/modules/messages/components/message-detail/detail-panels.js +27 -0
- package/dist/modules/messages/components/message-detail/detail-panels.js.map +7 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +52 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +7 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js +289 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsActions.js.map +7 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js +103 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.js.map +7 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js +78 -0
- package/dist/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js +94 -0
- package/dist/modules/messages/components/message-detail/panels/MainMessageHeader.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js +110 -0
- package/dist/modules/messages/components/message-detail/panels/MessageHeader.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js +58 -0
- package/dist/modules/messages/components/message-detail/panels/MessageListComponent.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/actions-panel.js +51 -0
- package/dist/modules/messages/components/message-detail/panels/actions-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/attachments-panel.js +66 -0
- package/dist/modules/messages/components/message-detail/panels/attachments-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/body-panel.js +20 -0
- package/dist/modules/messages/components/message-detail/panels/body-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js +36 -0
- package/dist/modules/messages/components/message-detail/panels/composer-dialogs.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/dialogs.js +96 -0
- package/dist/modules/messages/components/message-detail/panels/dialogs.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/index.js +25 -0
- package/dist/modules/messages/components/message-detail/panels/index.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/meta-panel.js +14 -0
- package/dist/modules/messages/components/message-detail/panels/meta-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js +51 -0
- package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js +54 -0
- package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +7 -0
- package/dist/modules/messages/components/message-detail/types.js +1 -0
- package/dist/modules/messages/components/message-detail/types.js.map +7 -0
- package/dist/modules/messages/components/message-detail/utils.js +54 -0
- package/dist/modules/messages/components/message-detail/utils.js.map +7 -0
- package/dist/modules/messages/components/utils/PriorityBadge.js +52 -0
- package/dist/modules/messages/components/utils/PriorityBadge.js.map +7 -0
- package/dist/modules/messages/components/utils/typeUiRegistry.js +77 -0
- package/dist/modules/messages/components/utils/typeUiRegistry.js.map +7 -0
- package/dist/modules/messages/data/entities.js +309 -0
- package/dist/modules/messages/data/entities.js.map +7 -0
- package/dist/modules/messages/data/validators.js +272 -0
- package/dist/modules/messages/data/validators.js.map +7 -0
- package/dist/modules/messages/emails/MessageEmail.js +108 -0
- package/dist/modules/messages/emails/MessageEmail.js.map +7 -0
- package/dist/modules/messages/events.js +24 -0
- package/dist/modules/messages/events.js.map +7 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.js +247 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +7 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js +9 -0
- package/dist/modules/messages/frontend/messages/view/[token]/page.meta.js.map +7 -0
- package/dist/modules/messages/index.js +21 -0
- package/dist/modules/messages/index.js.map +7 -0
- package/dist/modules/messages/lib/actions.js +141 -0
- package/dist/modules/messages/lib/actions.js.map +7 -0
- package/dist/modules/messages/lib/attachments.js +131 -0
- package/dist/modules/messages/lib/attachments.js.map +7 -0
- package/dist/modules/messages/lib/constants.js +7 -0
- package/dist/modules/messages/lib/constants.js.map +7 -0
- package/dist/modules/messages/lib/email-sender.js +201 -0
- package/dist/modules/messages/lib/email-sender.js.map +7 -0
- package/dist/modules/messages/lib/forwarding.js +179 -0
- package/dist/modules/messages/lib/forwarding.js.map +7 -0
- package/dist/modules/messages/lib/message-objects-registry.js +49 -0
- package/dist/modules/messages/lib/message-objects-registry.js.map +7 -0
- package/dist/modules/messages/lib/message-types-registry.js +41 -0
- package/dist/modules/messages/lib/message-types-registry.js.map +7 -0
- package/dist/modules/messages/lib/object-validation.js +20 -0
- package/dist/modules/messages/lib/object-validation.js.map +7 -0
- package/dist/modules/messages/lib/operationMetadata.js +21 -0
- package/dist/modules/messages/lib/operationMetadata.js.map +7 -0
- package/dist/modules/messages/lib/priorityUtils.js +61 -0
- package/dist/modules/messages/lib/priorityUtils.js.map +7 -0
- package/dist/modules/messages/lib/routeHelpers.js +44 -0
- package/dist/modules/messages/lib/routeHelpers.js.map +7 -0
- package/dist/modules/messages/message-objects.js +7 -0
- package/dist/modules/messages/message-objects.js.map +7 -0
- package/dist/modules/messages/message-types.js +67 -0
- package/dist/modules/messages/message-types.js.map +7 -0
- package/dist/modules/messages/migrations/Migration20260213181243.js +31 -0
- package/dist/modules/messages/migrations/Migration20260213181243.js.map +7 -0
- package/dist/modules/messages/migrations/Migration20260215165126.js +16 -0
- package/dist/modules/messages/migrations/Migration20260215165126.js.map +7 -0
- package/dist/modules/messages/notifications.js +27 -0
- package/dist/modules/messages/notifications.js.map +7 -0
- package/dist/modules/messages/setup.js +21 -0
- package/dist/modules/messages/setup.js.map +7 -0
- package/dist/modules/messages/subscribers/message-notification.js +108 -0
- package/dist/modules/messages/subscribers/message-notification.js.map +7 -0
- package/dist/modules/messages/workers/send-email.worker.js +253 -0
- package/dist/modules/messages/workers/send-email.worker.js.map +7 -0
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +30 -11
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +12 -6
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/lib/messageObjectPreviews.js +114 -0
- package/dist/modules/sales/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/sales/message-objects.js +57 -0
- package/dist/modules/sales/message-objects.js.map +7 -0
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +51 -0
- package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +7 -0
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +36 -0
- package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +7 -0
- package/dist/modules/sales/widgets/messages/index.js +7 -0
- package/dist/modules/sales/widgets/messages/index.js.map +7 -0
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +55 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +60 -1
- package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +2 -19
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/components/LeaveRequestDetail.js +112 -0
- package/dist/modules/staff/components/LeaveRequestDetail.js.map +7 -0
- package/dist/modules/staff/components/LeaveRequestForm.js +3 -1
- package/dist/modules/staff/components/LeaveRequestForm.js.map +2 -2
- package/dist/modules/staff/components/LeaveRequestPreview.js +43 -0
- package/dist/modules/staff/components/LeaveRequestPreview.js.map +7 -0
- package/dist/modules/staff/lib/messageObjectPreviews.js +148 -0
- package/dist/modules/staff/lib/messageObjectPreviews.js.map +7 -0
- package/dist/modules/staff/message-objects.js +104 -0
- package/dist/modules/staff/message-objects.js.map +7 -0
- package/dist/modules/staff/message-types.js +23 -0
- package/dist/modules/staff/message-types.js.map +7 -0
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +51 -0
- package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +7 -0
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +34 -0
- package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +7 -0
- package/dist/modules/staff/widgets/messages/index.js +7 -0
- package/dist/modules/staff/widgets/messages/index.js.map +7 -0
- package/generated/entities/message/index.ts +31 -0
- package/generated/entities/message_access_token/index.ts +8 -0
- package/generated/entities/message_confirmation/index.ts +9 -0
- package/generated/entities/message_object/index.ts +10 -0
- package/generated/entities/message_recipient/index.ts +14 -0
- package/generated/entities.ids.generated.ts +8 -0
- package/generated/entity-fields-registry.ts +10 -0
- package/jest.setup.ts +5 -0
- package/package.json +2 -2
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +20 -4
- package/src/modules/customers/i18n/de.json +4 -0
- package/src/modules/customers/i18n/en.json +4 -0
- package/src/modules/customers/i18n/es.json +4 -0
- package/src/modules/customers/i18n/pl.json +4 -0
- package/src/modules/customers/lib/messageObjectPreviews.ts +154 -0
- package/src/modules/customers/message-objects.ts +70 -0
- package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +57 -0
- package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +49 -0
- package/src/modules/customers/widgets/messages/index.ts +2 -0
- package/src/modules/messages/acl.ts +11 -0
- package/src/modules/messages/api/[id]/actions/[actionId]/route.ts +103 -0
- package/src/modules/messages/api/[id]/archive/route.ts +138 -0
- package/src/modules/messages/api/[id]/attachments/route.ts +217 -0
- package/src/modules/messages/api/[id]/confirmation/route.ts +73 -0
- package/src/modules/messages/api/[id]/conversation/archive/route.ts +69 -0
- package/src/modules/messages/api/[id]/conversation/read/route.ts +69 -0
- package/src/modules/messages/api/[id]/conversation/route.ts +69 -0
- package/src/modules/messages/api/[id]/forward/route.ts +87 -0
- package/src/modules/messages/api/[id]/forward-preview/route.ts +75 -0
- package/src/modules/messages/api/[id]/read/route.ts +138 -0
- package/src/modules/messages/api/[id]/reply/route.ts +89 -0
- package/src/modules/messages/api/[id]/route.ts +401 -0
- package/src/modules/messages/api/object-types/route.ts +54 -0
- package/src/modules/messages/api/openapi.ts +261 -0
- package/src/modules/messages/api/route.ts +374 -0
- package/src/modules/messages/api/token/[token]/route.ts +103 -0
- package/src/modules/messages/api/types/route.ts +39 -0
- package/src/modules/messages/api/unread-count/route.ts +55 -0
- package/src/modules/messages/backend/messages/[id]/page.meta.ts +12 -0
- package/src/modules/messages/backend/messages/[id]/page.tsx +12 -0
- package/src/modules/messages/backend/messages/compose/page.meta.ts +13 -0
- package/src/modules/messages/backend/messages/compose/page.tsx +12 -0
- package/src/modules/messages/backend/page.meta.ts +31 -0
- package/src/modules/messages/backend/page.tsx +12 -0
- package/src/modules/messages/commands/actions.ts +307 -0
- package/src/modules/messages/commands/attachments.ts +227 -0
- package/src/modules/messages/commands/confirmations.ts +183 -0
- package/src/modules/messages/commands/conversation.ts +292 -0
- package/src/modules/messages/commands/messages.ts +845 -0
- package/src/modules/messages/commands/recipients.ts +281 -0
- package/src/modules/messages/commands/shared.ts +350 -0
- package/src/modules/messages/commands/tokens.ts +80 -0
- package/src/modules/messages/components/ComposeMessagePageClient.tsx +23 -0
- package/src/modules/messages/components/MessageDetailPageClient.tsx +287 -0
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +469 -0
- package/src/modules/messages/components/confirmation/MessageConfirmationActions.tsx +35 -0
- package/src/modules/messages/components/confirmation/MessageConfirmationContent.tsx +88 -0
- package/src/modules/messages/components/defaults/DefaultMessageActions.tsx +37 -0
- package/src/modules/messages/components/defaults/DefaultMessageContent.tsx +21 -0
- package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +102 -0
- package/src/modules/messages/components/defaults/MessageRecordObjectDetail.tsx +114 -0
- package/src/modules/messages/components/defaults/MessageRecordObjectPreview.tsx +74 -0
- package/src/modules/messages/components/message-detail/detail-panels.ts +13 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +56 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsActions.ts +367 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsConversation.ts +134 -0
- package/src/modules/messages/components/message-detail/hooks/useMessageDetailsQueries.ts +102 -0
- package/src/modules/messages/components/message-detail/panels/MainMessageHeader.tsx +108 -0
- package/src/modules/messages/components/message-detail/panels/MessageHeader.tsx +144 -0
- package/src/modules/messages/components/message-detail/panels/MessageListComponent.tsx +63 -0
- package/src/modules/messages/components/message-detail/panels/actions-panel.tsx +66 -0
- package/src/modules/messages/components/message-detail/panels/attachments-panel.tsx +86 -0
- package/src/modules/messages/components/message-detail/panels/body-panel.tsx +32 -0
- package/src/modules/messages/components/message-detail/panels/composer-dialogs.tsx +42 -0
- package/src/modules/messages/components/message-detail/panels/dialogs.tsx +107 -0
- package/src/modules/messages/components/message-detail/panels/index.ts +11 -0
- package/src/modules/messages/components/message-detail/panels/meta-panel.tsx +19 -0
- package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +65 -0
- package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +65 -0
- package/src/modules/messages/components/message-detail/types.ts +114 -0
- package/src/modules/messages/components/message-detail/utils.ts +62 -0
- package/src/modules/messages/components/utils/PriorityBadge.tsx +63 -0
- package/src/modules/messages/components/utils/typeUiRegistry.ts +106 -0
- package/src/modules/messages/data/entities.ts +284 -0
- package/src/modules/messages/data/validators.ts +297 -0
- package/src/modules/messages/emails/MessageEmail.tsx +143 -0
- package/src/modules/messages/events.ts +24 -0
- package/src/modules/messages/frontend/messages/view/[token]/page.meta.ts +5 -0
- package/src/modules/messages/frontend/messages/view/[token]/page.tsx +389 -0
- package/src/modules/messages/i18n/de.json +240 -0
- package/src/modules/messages/i18n/en.json +240 -0
- package/src/modules/messages/i18n/es.json +240 -0
- package/src/modules/messages/i18n/pl.json +240 -0
- package/src/modules/messages/index.ts +19 -0
- package/src/modules/messages/lib/actions.ts +204 -0
- package/src/modules/messages/lib/attachments.ts +197 -0
- package/src/modules/messages/lib/constants.ts +2 -0
- package/src/modules/messages/lib/email-sender.ts +255 -0
- package/src/modules/messages/lib/forwarding.ts +240 -0
- package/src/modules/messages/lib/message-objects-registry.ts +60 -0
- package/src/modules/messages/lib/message-types-registry.ts +48 -0
- package/src/modules/messages/lib/object-validation.ts +26 -0
- package/src/modules/messages/lib/operationMetadata.ts +43 -0
- package/src/modules/messages/lib/priorityUtils.ts +76 -0
- package/src/modules/messages/lib/routeHelpers.ts +65 -0
- package/src/modules/messages/message-objects.ts +5 -0
- package/src/modules/messages/message-types.ts +65 -0
- package/src/modules/messages/migrations/.snapshot-open-mercato.json +957 -0
- package/src/modules/messages/migrations/Migration20260213181243.ts +34 -0
- package/src/modules/messages/migrations/Migration20260215165126.ts +16 -0
- package/src/modules/messages/notifications.ts +25 -0
- package/src/modules/messages/setup.ts +19 -0
- package/src/modules/messages/subscribers/message-notification.ts +138 -0
- package/src/modules/messages/workers/send-email.worker.ts +321 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -7
- package/src/modules/sales/commands/payments.ts +12 -6
- package/src/modules/sales/i18n/de.json +3 -0
- package/src/modules/sales/i18n/en.json +3 -0
- package/src/modules/sales/i18n/es.json +3 -0
- package/src/modules/sales/i18n/pl.json +3 -0
- package/src/modules/sales/lib/messageObjectPreviews.ts +150 -0
- package/src/modules/sales/message-objects.ts +56 -0
- package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +57 -0
- package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +46 -0
- package/src/modules/sales/widgets/messages/index.ts +2 -0
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +54 -0
- package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +58 -0
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +2 -32
- package/src/modules/staff/components/LeaveRequestDetail.tsx +135 -0
- package/src/modules/staff/components/LeaveRequestForm.tsx +3 -0
- package/src/modules/staff/components/LeaveRequestPreview.tsx +74 -0
- package/src/modules/staff/i18n/de.json +8 -0
- package/src/modules/staff/i18n/en.json +8 -0
- package/src/modules/staff/i18n/es.json +8 -0
- package/src/modules/staff/i18n/pl.json +8 -0
- package/src/modules/staff/lib/messageObjectPreviews.ts +182 -0
- package/src/modules/staff/message-objects.ts +102 -0
- package/src/modules/staff/message-types.ts +21 -0
- package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +57 -0
- package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +44 -0
- package/src/modules/staff/widgets/messages/index.ts +2 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
|
|
3
|
+
export class Migration20260213181243 extends Migration {
|
|
4
|
+
|
|
5
|
+
override async up(): Promise<void> {
|
|
6
|
+
this.addSql(`create table "messages" ("id" uuid not null default gen_random_uuid(), "type" text not null default 'default', "thread_id" uuid null, "parent_message_id" uuid null, "sender_user_id" uuid not null, "subject" text not null, "body" text not null, "body_format" text not null default 'text', "priority" text not null default 'normal', "status" text not null default 'draft', "is_draft" boolean not null default true, "sent_at" timestamptz null, "action_data" jsonb null, "action_result" jsonb null, "action_taken" text null, "action_taken_by_user_id" uuid null, "action_taken_at" timestamptz null, "send_via_email" boolean not null default false, "tenant_id" uuid not null, "organization_id" uuid null, "created_at" timestamptz not null, "updated_at" timestamptz not null, "deleted_at" timestamptz null, "visibility" text null, "source_entity_type" text null, "source_entity_id" uuid null, "external_email" text null, "external_name" text null, "external_email_sent_at" timestamptz null, "external_email_failed_at" timestamptz null, "external_email_error" text null, constraint "messages_pkey" primary key ("id"));`);
|
|
7
|
+
this.addSql(`create index "messages_tenant_idx" on "messages" ("tenant_id", "organization_id");`);
|
|
8
|
+
this.addSql(`create index "messages_type_idx" on "messages" ("type", "tenant_id");`);
|
|
9
|
+
this.addSql(`create index "messages_thread_idx" on "messages" ("thread_id");`);
|
|
10
|
+
this.addSql(`create index "messages_sender_idx" on "messages" ("sender_user_id", "sent_at");`);
|
|
11
|
+
|
|
12
|
+
this.addSql(`create table "message_access_tokens" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "recipient_user_id" uuid not null, "token" text not null, "expires_at" timestamptz not null, "used_at" timestamptz null, "use_count" int not null default 0, "created_at" timestamptz not null, constraint "message_access_tokens_pkey" primary key ("id"));`);
|
|
13
|
+
this.addSql(`alter table "message_access_tokens" add constraint "message_access_tokens_token_unique" unique ("token");`);
|
|
14
|
+
this.addSql(`create index "message_access_tokens_message_idx" on "message_access_tokens" ("message_id");`);
|
|
15
|
+
this.addSql(`create index "message_access_tokens_token_idx" on "message_access_tokens" ("token");`);
|
|
16
|
+
|
|
17
|
+
this.addSql(`create table "message_objects" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "entity_module" text not null, "entity_type" text not null, "entity_id" uuid not null, "action_required" boolean not null default false, "action_type" text null, "action_label" text null, "entity_snapshot" jsonb null, "created_at" timestamptz not null, constraint "message_objects_pkey" primary key ("id"));`);
|
|
18
|
+
this.addSql(`create index "message_objects_entity_idx" on "message_objects" ("entity_type", "entity_id");`);
|
|
19
|
+
this.addSql(`create index "message_objects_message_idx" on "message_objects" ("message_id");`);
|
|
20
|
+
|
|
21
|
+
this.addSql(`create table "message_recipients" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "recipient_user_id" uuid not null, "recipient_type" text not null default 'to', "status" text not null default 'unread', "read_at" timestamptz null, "archived_at" timestamptz null, "deleted_at" timestamptz null, "email_sent_at" timestamptz null, "email_delivered_at" timestamptz null, "email_opened_at" timestamptz null, "email_failed_at" timestamptz null, "email_error" text null, "created_at" timestamptz not null, constraint "message_recipients_pkey" primary key ("id"));`);
|
|
22
|
+
this.addSql(`alter table "message_recipients" add constraint "message_recipients_message_user_unique" unique ("message_id", "recipient_user_id");`);
|
|
23
|
+
this.addSql(`create index "message_recipients_message_idx" on "message_recipients" ("message_id");`);
|
|
24
|
+
this.addSql(`create index "message_recipients_user_idx" on "message_recipients" ("recipient_user_id", "status");`);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
override async down(): Promise<void> {
|
|
28
|
+
this.addSql(`drop table if exists "message_recipients" cascade;`);
|
|
29
|
+
this.addSql(`drop table if exists "message_objects" cascade;`);
|
|
30
|
+
this.addSql(`drop table if exists "message_access_tokens" cascade;`);
|
|
31
|
+
this.addSql(`drop table if exists "messages" cascade;`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Migration } from '@mikro-orm/migrations';
|
|
2
|
+
|
|
3
|
+
export class Migration20260215165126 extends Migration {
|
|
4
|
+
|
|
5
|
+
override async up(): Promise<void> {
|
|
6
|
+
this.addSql(`create table "message_confirmations" ("id" uuid not null default gen_random_uuid(), "message_id" uuid not null, "tenant_id" uuid not null, "organization_id" uuid null, "confirmed" boolean not null default true, "confirmed_by_user_id" uuid null, "confirmed_at" timestamptz null, "created_at" timestamptz not null, "updated_at" timestamptz not null, constraint "message_confirmations_pkey" primary key ("id"));`);
|
|
7
|
+
this.addSql(`create index "message_confirmations_scope_idx" on "message_confirmations" ("tenant_id", "organization_id");`);
|
|
8
|
+
this.addSql(`create index "message_confirmations_message_idx" on "message_confirmations" ("message_id");`);
|
|
9
|
+
this.addSql(`alter table "message_confirmations" add constraint "message_confirmations_message_unique" unique ("message_id");`);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
override async down(): Promise<void> {
|
|
13
|
+
this.addSql(`drop table if exists "message_confirmations" cascade;`);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { NotificationTypeDefinition } from '@open-mercato/shared/modules/notifications/types'
|
|
2
|
+
|
|
3
|
+
export const notificationTypes: NotificationTypeDefinition[] = [
|
|
4
|
+
{
|
|
5
|
+
type: 'messages.new',
|
|
6
|
+
module: 'messages',
|
|
7
|
+
titleKey: 'messages.notifications.new.title',
|
|
8
|
+
bodyKey: 'messages.notifications.new.body',
|
|
9
|
+
icon: 'mail',
|
|
10
|
+
severity: 'info',
|
|
11
|
+
actions: [
|
|
12
|
+
{
|
|
13
|
+
id: 'view',
|
|
14
|
+
labelKey: 'common.view',
|
|
15
|
+
variant: 'outline',
|
|
16
|
+
href: '/backend/messages/{sourceEntityId}',
|
|
17
|
+
icon: 'external-link',
|
|
18
|
+
},
|
|
19
|
+
],
|
|
20
|
+
linkHref: '/backend/messages/{sourceEntityId}',
|
|
21
|
+
expiresAfterHours: 168,
|
|
22
|
+
},
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
export default notificationTypes
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ModuleSetupConfig } from '@open-mercato/shared/modules/setup'
|
|
2
|
+
|
|
3
|
+
export const setup: ModuleSetupConfig = {
|
|
4
|
+
defaultRoleFeatures: {
|
|
5
|
+
superadmin: ['messages.*'],
|
|
6
|
+
admin: [
|
|
7
|
+
'messages.*',
|
|
8
|
+
],
|
|
9
|
+
employee: [
|
|
10
|
+
'messages.view',
|
|
11
|
+
'messages.compose',
|
|
12
|
+
'messages.attach',
|
|
13
|
+
'messages.attach_files',
|
|
14
|
+
'messages.actions',
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default setup
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
3
|
+
import { createQueue } from '@open-mercato/queue'
|
|
4
|
+
import { buildBatchNotificationFromType } from '../../notifications/lib/notificationBuilder'
|
|
5
|
+
import { resolveNotificationService } from '../../notifications/lib/notificationService'
|
|
6
|
+
import {
|
|
7
|
+
MESSAGES_EMAIL_QUEUE_NAME,
|
|
8
|
+
type SendMessageEmailJob,
|
|
9
|
+
} from '../workers/send-email.worker'
|
|
10
|
+
import { User } from '../../auth/data/entities'
|
|
11
|
+
import { Message } from '../data/entities'
|
|
12
|
+
import { notificationTypes } from '../notifications'
|
|
13
|
+
|
|
14
|
+
export const metadata = {
|
|
15
|
+
event: 'messages.message.sent',
|
|
16
|
+
persistent: true,
|
|
17
|
+
id: 'messages:queue-email-delivery',
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
type MessageSentPayload = {
|
|
21
|
+
messageId: string
|
|
22
|
+
senderUserId: string
|
|
23
|
+
recipientUserIds: string[]
|
|
24
|
+
sendViaEmail: boolean
|
|
25
|
+
externalEmail?: string | null
|
|
26
|
+
forwardedFrom?: string
|
|
27
|
+
replyTo?: string
|
|
28
|
+
tenantId: string
|
|
29
|
+
organizationId?: string | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ResolverContext = {
|
|
33
|
+
resolve: <T = unknown>(name: string) => T
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function resolveNotificationVariables(payload: MessageSentPayload, ctx: ResolverContext): Promise<{ title: string; from: string }> {
|
|
37
|
+
try {
|
|
38
|
+
const em = ctx.resolve<EntityManager>('em')?.fork()
|
|
39
|
+
if (!em) return { title: '', from: '' }
|
|
40
|
+
|
|
41
|
+
const scope = {
|
|
42
|
+
tenantId: payload.tenantId,
|
|
43
|
+
organizationId: payload.organizationId ?? null,
|
|
44
|
+
}
|
|
45
|
+
const whereUser: { id: string; tenantId: string; deletedAt: null; organizationId?: string | null } = {
|
|
46
|
+
id: payload.senderUserId,
|
|
47
|
+
tenantId: payload.tenantId,
|
|
48
|
+
deletedAt: null,
|
|
49
|
+
}
|
|
50
|
+
if (payload.organizationId !== undefined) {
|
|
51
|
+
whereUser.organizationId = payload.organizationId
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const [message, sender] = await Promise.all([
|
|
55
|
+
findOneWithDecryption(
|
|
56
|
+
em,
|
|
57
|
+
Message,
|
|
58
|
+
{
|
|
59
|
+
id: payload.messageId,
|
|
60
|
+
tenantId: payload.tenantId,
|
|
61
|
+
deletedAt: null,
|
|
62
|
+
},
|
|
63
|
+
undefined,
|
|
64
|
+
scope,
|
|
65
|
+
),
|
|
66
|
+
findOneWithDecryption(
|
|
67
|
+
em,
|
|
68
|
+
User,
|
|
69
|
+
whereUser,
|
|
70
|
+
undefined,
|
|
71
|
+
scope,
|
|
72
|
+
),
|
|
73
|
+
])
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
title: typeof message?.subject === 'string' ? message.subject : '',
|
|
77
|
+
from: typeof sender?.name === 'string' && sender.name.trim().length > 0
|
|
78
|
+
? sender.name
|
|
79
|
+
: typeof sender?.email === 'string'
|
|
80
|
+
? sender.email
|
|
81
|
+
: '',
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
return { title: '', from: '' }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
export default async function handle(payload: MessageSentPayload, ctx: ResolverContext): Promise<void> {
|
|
90
|
+
const uniqueRecipientUserIds = Array.from(new Set(payload.recipientUserIds))
|
|
91
|
+
|
|
92
|
+
const typeDef = notificationTypes.find((type) => type.type === 'messages.new')
|
|
93
|
+
if (typeDef && uniqueRecipientUserIds.length > 0) {
|
|
94
|
+
const variables = await resolveNotificationVariables(payload, ctx)
|
|
95
|
+
const notificationService = resolveNotificationService(ctx)
|
|
96
|
+
const notificationInput = buildBatchNotificationFromType(typeDef, {
|
|
97
|
+
recipientUserIds: uniqueRecipientUserIds,
|
|
98
|
+
titleVariables: variables,
|
|
99
|
+
bodyVariables: variables,
|
|
100
|
+
sourceEntityType: 'message',
|
|
101
|
+
sourceEntityId: payload.messageId,
|
|
102
|
+
linkHref: `/backend/messages/${payload.messageId}`,
|
|
103
|
+
})
|
|
104
|
+
await notificationService.createBatch(notificationInput, {
|
|
105
|
+
tenantId: payload.tenantId,
|
|
106
|
+
organizationId: payload.organizationId ?? null,
|
|
107
|
+
})
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!payload.sendViaEmail) {
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const strategy = process.env.QUEUE_STRATEGY === 'async' ? 'async' : 'local'
|
|
115
|
+
|
|
116
|
+
const emailQueue = createQueue<SendMessageEmailJob>(MESSAGES_EMAIL_QUEUE_NAME, strategy)
|
|
117
|
+
|
|
118
|
+
for (const recipientUserId of uniqueRecipientUserIds) {
|
|
119
|
+
await emailQueue.enqueue({
|
|
120
|
+
type: 'recipient',
|
|
121
|
+
messageId: payload.messageId,
|
|
122
|
+
recipientUserId,
|
|
123
|
+
tenantId: payload.tenantId,
|
|
124
|
+
organizationId: payload.organizationId ?? null,
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const externalEmail = payload.externalEmail?.trim()
|
|
129
|
+
if (externalEmail) {
|
|
130
|
+
await emailQueue.enqueue({
|
|
131
|
+
type: 'external',
|
|
132
|
+
messageId: payload.messageId,
|
|
133
|
+
email: externalEmail,
|
|
134
|
+
tenantId: payload.tenantId,
|
|
135
|
+
organizationId: payload.organizationId ?? null,
|
|
136
|
+
})
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'
|
|
3
|
+
import { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
4
|
+
import { User } from '../../auth/data/entities'
|
|
5
|
+
import { Message, MessageObject, MessageRecipient } from '../data/entities'
|
|
6
|
+
import { emitMessagesEvent } from '../events'
|
|
7
|
+
import { getMessageEmailAttachments } from '../lib/attachments'
|
|
8
|
+
import {
|
|
9
|
+
sendMessageEmailToExternal,
|
|
10
|
+
sendMessageEmailToRecipient,
|
|
11
|
+
} from '../lib/email-sender'
|
|
12
|
+
|
|
13
|
+
export const MESSAGES_EMAIL_QUEUE_NAME = 'messages-email'
|
|
14
|
+
|
|
15
|
+
export type SendMessageEmailToRecipientJob = {
|
|
16
|
+
type: 'recipient'
|
|
17
|
+
messageId: string
|
|
18
|
+
recipientUserId: string
|
|
19
|
+
tenantId: string
|
|
20
|
+
organizationId?: string | null
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type SendMessageEmailToExternalJob = {
|
|
24
|
+
type: 'external'
|
|
25
|
+
messageId: string
|
|
26
|
+
email: string
|
|
27
|
+
tenantId: string
|
|
28
|
+
organizationId?: string | null
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type SendMessageEmailJob = SendMessageEmailToRecipientJob | SendMessageEmailToExternalJob
|
|
32
|
+
|
|
33
|
+
export const metadata: WorkerMeta = {
|
|
34
|
+
queue: MESSAGES_EMAIL_QUEUE_NAME,
|
|
35
|
+
id: 'messages:send-email',
|
|
36
|
+
concurrency: 10,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type HandlerContext = {
|
|
40
|
+
resolve: <T = unknown>(name: string) => T
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function emitEmailDeliveryEvent(
|
|
44
|
+
ctx: HandlerContext,
|
|
45
|
+
eventId: 'messages.message.email_sent' | 'messages.message.email_failed',
|
|
46
|
+
payload: {
|
|
47
|
+
messageId: string
|
|
48
|
+
target: 'recipient' | 'external'
|
|
49
|
+
recipientUserId?: string
|
|
50
|
+
email?: string
|
|
51
|
+
error?: string
|
|
52
|
+
tenantId: string
|
|
53
|
+
organizationId?: string | null
|
|
54
|
+
}
|
|
55
|
+
) {
|
|
56
|
+
const eventBus = ctx.resolve<{ emit?: unknown } | null>('eventBus')
|
|
57
|
+
if (!eventBus || typeof eventBus !== 'object' || typeof (eventBus as { emit?: unknown }).emit !== 'function') {
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
await emitMessagesEvent(eventId, payload, { persistent: true })
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function resolveSender(em: EntityManager, message: Message) {
|
|
64
|
+
const sender = await findOneWithDecryption(
|
|
65
|
+
em,
|
|
66
|
+
User,
|
|
67
|
+
{
|
|
68
|
+
id: message.senderUserId,
|
|
69
|
+
tenantId: message.tenantId,
|
|
70
|
+
deletedAt: null,
|
|
71
|
+
},
|
|
72
|
+
undefined,
|
|
73
|
+
{ tenantId: message.tenantId, organizationId: message.organizationId ?? null }
|
|
74
|
+
)
|
|
75
|
+
return {
|
|
76
|
+
name: sender?.name ?? null,
|
|
77
|
+
email: sender?.email ?? null,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async function resolveMessageScope(
|
|
82
|
+
em: EntityManager,
|
|
83
|
+
payload: SendMessageEmailJob
|
|
84
|
+
) {
|
|
85
|
+
return await em.findOne(Message, {
|
|
86
|
+
id: payload.messageId,
|
|
87
|
+
tenantId: payload.tenantId,
|
|
88
|
+
organizationId: payload.organizationId ?? null,
|
|
89
|
+
deletedAt: null,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function claimRecipientDelivery(
|
|
94
|
+
em: EntityManager,
|
|
95
|
+
payload: SendMessageEmailToRecipientJob,
|
|
96
|
+
): Promise<Date | null> {
|
|
97
|
+
const claimTimestamp = new Date()
|
|
98
|
+
const updatedRows = await em.nativeUpdate(
|
|
99
|
+
MessageRecipient,
|
|
100
|
+
{
|
|
101
|
+
messageId: payload.messageId,
|
|
102
|
+
recipientUserId: payload.recipientUserId,
|
|
103
|
+
emailSentAt: null,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
emailSentAt: claimTimestamp,
|
|
107
|
+
emailFailedAt: null,
|
|
108
|
+
emailError: null,
|
|
109
|
+
},
|
|
110
|
+
)
|
|
111
|
+
return updatedRows > 0 ? claimTimestamp : null
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function releaseRecipientClaim(
|
|
115
|
+
em: EntityManager,
|
|
116
|
+
payload: SendMessageEmailToRecipientJob,
|
|
117
|
+
claimTimestamp: Date,
|
|
118
|
+
errorMessage: string,
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
await em.nativeUpdate(
|
|
121
|
+
MessageRecipient,
|
|
122
|
+
{
|
|
123
|
+
messageId: payload.messageId,
|
|
124
|
+
recipientUserId: payload.recipientUserId,
|
|
125
|
+
emailSentAt: claimTimestamp,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
emailSentAt: null,
|
|
129
|
+
emailFailedAt: new Date(),
|
|
130
|
+
emailError: errorMessage,
|
|
131
|
+
},
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export async function claimExternalDelivery(
|
|
136
|
+
em: EntityManager,
|
|
137
|
+
payload: SendMessageEmailToExternalJob,
|
|
138
|
+
): Promise<Date | null> {
|
|
139
|
+
const claimTimestamp = new Date()
|
|
140
|
+
const updatedRows = await em.nativeUpdate(
|
|
141
|
+
Message,
|
|
142
|
+
{
|
|
143
|
+
id: payload.messageId,
|
|
144
|
+
tenantId: payload.tenantId,
|
|
145
|
+
organizationId: payload.organizationId ?? null,
|
|
146
|
+
externalEmailSentAt: null,
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
externalEmailSentAt: claimTimestamp,
|
|
150
|
+
externalEmailFailedAt: null,
|
|
151
|
+
externalEmailError: null,
|
|
152
|
+
},
|
|
153
|
+
)
|
|
154
|
+
return updatedRows > 0 ? claimTimestamp : null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export async function releaseExternalClaim(
|
|
158
|
+
em: EntityManager,
|
|
159
|
+
payload: SendMessageEmailToExternalJob,
|
|
160
|
+
claimTimestamp: Date,
|
|
161
|
+
errorMessage: string,
|
|
162
|
+
): Promise<void> {
|
|
163
|
+
await em.nativeUpdate(
|
|
164
|
+
Message,
|
|
165
|
+
{
|
|
166
|
+
id: payload.messageId,
|
|
167
|
+
tenantId: payload.tenantId,
|
|
168
|
+
organizationId: payload.organizationId ?? null,
|
|
169
|
+
externalEmailSentAt: claimTimestamp,
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
externalEmailSentAt: null,
|
|
173
|
+
externalEmailFailedAt: new Date(),
|
|
174
|
+
externalEmailError: errorMessage,
|
|
175
|
+
},
|
|
176
|
+
)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export default async function handle(
|
|
180
|
+
job: QueuedJob<SendMessageEmailJob>,
|
|
181
|
+
ctx: JobContext & HandlerContext
|
|
182
|
+
): Promise<void> {
|
|
183
|
+
const { payload } = job
|
|
184
|
+
const em = (ctx.resolve('em') as EntityManager).fork()
|
|
185
|
+
|
|
186
|
+
const message = await resolveMessageScope(em, payload)
|
|
187
|
+
if (!message) {
|
|
188
|
+
console.error('[messages:send-email] Message not found', payload.messageId)
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const objects = await em.find(MessageObject, { messageId: message.id })
|
|
193
|
+
const attachments = await getMessageEmailAttachments(
|
|
194
|
+
em,
|
|
195
|
+
message.id,
|
|
196
|
+
message.organizationId ?? null,
|
|
197
|
+
message.tenantId
|
|
198
|
+
)
|
|
199
|
+
const sender = await resolveSender(em, message)
|
|
200
|
+
|
|
201
|
+
if (payload.type === 'external') {
|
|
202
|
+
const externalClaimTimestamp = await claimExternalDelivery(em, payload)
|
|
203
|
+
if (!externalClaimTimestamp) {
|
|
204
|
+
return
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
await sendMessageEmailToExternal({
|
|
209
|
+
message,
|
|
210
|
+
email: payload.email,
|
|
211
|
+
sender,
|
|
212
|
+
objects,
|
|
213
|
+
attachments,
|
|
214
|
+
})
|
|
215
|
+
await emitEmailDeliveryEvent(ctx, 'messages.message.email_sent', {
|
|
216
|
+
messageId: message.id,
|
|
217
|
+
target: 'external',
|
|
218
|
+
email: payload.email,
|
|
219
|
+
tenantId: message.tenantId,
|
|
220
|
+
organizationId: message.organizationId ?? null,
|
|
221
|
+
})
|
|
222
|
+
} catch (error) {
|
|
223
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
224
|
+
await releaseExternalClaim(
|
|
225
|
+
em,
|
|
226
|
+
payload,
|
|
227
|
+
externalClaimTimestamp,
|
|
228
|
+
errorMessage,
|
|
229
|
+
)
|
|
230
|
+
await emitEmailDeliveryEvent(ctx, 'messages.message.email_failed', {
|
|
231
|
+
messageId: message.id,
|
|
232
|
+
target: 'external',
|
|
233
|
+
email: payload.email,
|
|
234
|
+
error: errorMessage,
|
|
235
|
+
tenantId: message.tenantId,
|
|
236
|
+
organizationId: message.organizationId ?? null,
|
|
237
|
+
})
|
|
238
|
+
console.error('[messages:send-email] External email send failed', error)
|
|
239
|
+
}
|
|
240
|
+
return
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const recipientRecord = await em.findOne(MessageRecipient, {
|
|
244
|
+
messageId: payload.messageId,
|
|
245
|
+
recipientUserId: payload.recipientUserId,
|
|
246
|
+
})
|
|
247
|
+
if (!recipientRecord) {
|
|
248
|
+
console.error('[messages:send-email] Recipient row not found', payload)
|
|
249
|
+
return
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (recipientRecord.emailSentAt) {
|
|
253
|
+
return
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const recipientClaimTimestamp = await claimRecipientDelivery(em, payload)
|
|
257
|
+
if (!recipientClaimTimestamp) {
|
|
258
|
+
return
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const recipientUser = await findOneWithDecryption(
|
|
262
|
+
em,
|
|
263
|
+
User,
|
|
264
|
+
{
|
|
265
|
+
id: payload.recipientUserId,
|
|
266
|
+
tenantId: message.tenantId,
|
|
267
|
+
deletedAt: null,
|
|
268
|
+
},
|
|
269
|
+
undefined,
|
|
270
|
+
{ tenantId: message.tenantId, organizationId: message.organizationId ?? null }
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
const recipientEmail = recipientUser?.email?.trim()
|
|
274
|
+
if (!recipientEmail) {
|
|
275
|
+
await releaseRecipientClaim(
|
|
276
|
+
em,
|
|
277
|
+
payload,
|
|
278
|
+
recipientClaimTimestamp,
|
|
279
|
+
'Recipient has no email address',
|
|
280
|
+
)
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
await sendMessageEmailToRecipient({
|
|
286
|
+
em,
|
|
287
|
+
message,
|
|
288
|
+
recipientUserId: payload.recipientUserId,
|
|
289
|
+
recipientEmail,
|
|
290
|
+
sender,
|
|
291
|
+
objects,
|
|
292
|
+
attachments,
|
|
293
|
+
})
|
|
294
|
+
await emitEmailDeliveryEvent(ctx, 'messages.message.email_sent', {
|
|
295
|
+
messageId: message.id,
|
|
296
|
+
target: 'recipient',
|
|
297
|
+
recipientUserId: payload.recipientUserId,
|
|
298
|
+
email: recipientEmail,
|
|
299
|
+
tenantId: message.tenantId,
|
|
300
|
+
organizationId: message.organizationId ?? null,
|
|
301
|
+
})
|
|
302
|
+
} catch (error) {
|
|
303
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
304
|
+
await releaseRecipientClaim(
|
|
305
|
+
em,
|
|
306
|
+
payload,
|
|
307
|
+
recipientClaimTimestamp,
|
|
308
|
+
errorMessage,
|
|
309
|
+
)
|
|
310
|
+
await emitEmailDeliveryEvent(ctx, 'messages.message.email_failed', {
|
|
311
|
+
messageId: message.id,
|
|
312
|
+
target: 'recipient',
|
|
313
|
+
recipientUserId: payload.recipientUserId,
|
|
314
|
+
email: recipientEmail,
|
|
315
|
+
error: errorMessage,
|
|
316
|
+
tenantId: message.tenantId,
|
|
317
|
+
organizationId: message.organizationId ?? null,
|
|
318
|
+
})
|
|
319
|
+
console.error('[messages:send-email] Recipient email send failed', error)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
@@ -24,6 +24,7 @@ import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, D
|
|
|
24
24
|
import { ArrowRightLeft, Building2, CreditCard, Mail, Pencil, Plus, Send, Store, Truck, UserRound, Wand2, X } from 'lucide-react'
|
|
25
25
|
import { FormHeader, type ActionItem } from '@open-mercato/ui/backend/forms'
|
|
26
26
|
import { VersionHistoryAction } from '@open-mercato/ui/backend/version-history'
|
|
27
|
+
import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
|
|
27
28
|
import Link from 'next/link'
|
|
28
29
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
29
30
|
import { apiCall, apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
@@ -4425,13 +4426,28 @@ export default function SalesDocumentDetailPage({
|
|
|
4425
4426
|
backHref={kind === 'order' ? '/backend/sales/orders' : '/backend/sales/quotes'}
|
|
4426
4427
|
backLabel={t('sales.documents.detail.back', 'Back to documents')}
|
|
4427
4428
|
utilityActions={record ? (
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4429
|
+
<>
|
|
4430
|
+
<SendObjectMessageDialog
|
|
4431
|
+
object={{
|
|
4432
|
+
entityModule: 'sales',
|
|
4433
|
+
entityType: kind,
|
|
4434
|
+
entityId: record.id,
|
|
4435
|
+
sourceEntityType: kind === 'order' ? 'sales.order' : 'sales.quote',
|
|
4436
|
+
sourceEntityId: record.id,
|
|
4437
|
+
}}
|
|
4438
|
+
defaultValues={{
|
|
4439
|
+
sourceEntityType: kind === 'order' ? 'sales.order' : 'sales.quote',
|
|
4440
|
+
sourceEntityId: record.id,
|
|
4441
|
+
}}
|
|
4442
|
+
/>
|
|
4443
|
+
<VersionHistoryAction
|
|
4444
|
+
config={{
|
|
4445
|
+
resourceKind: kind === 'order' ? 'sales.order' : 'sales.quote',
|
|
4446
|
+
resourceId: record.id,
|
|
4447
|
+
}}
|
|
4448
|
+
t={t}
|
|
4449
|
+
/>
|
|
4450
|
+
</>
|
|
4435
4451
|
) : null}
|
|
4436
4452
|
entityTypeLabel={kind === 'order'
|
|
4437
4453
|
? t('sales.documents.detail.order', 'Sales order')
|
|
@@ -564,21 +564,27 @@ const updatePaymentCommand: CommandHandler<
|
|
|
564
564
|
},
|
|
565
565
|
async execute(rawInput, ctx) {
|
|
566
566
|
const input = paymentUpdateSchema.parse(rawInput ?? {})
|
|
567
|
-
ensureTenantScope(ctx, input.tenantId)
|
|
568
|
-
ensureOrganizationScope(ctx, input.organizationId)
|
|
569
567
|
const em = (ctx.container.resolve('em') as EntityManager).fork()
|
|
570
568
|
const { translate } = await resolveTranslations()
|
|
569
|
+
const scopeSeed = assertFound(
|
|
570
|
+
await em.findOne(SalesPayment, { id: input.id }),
|
|
571
|
+
'sales.payments.not_found'
|
|
572
|
+
)
|
|
573
|
+
const resolvedTenantId = input.tenantId ?? scopeSeed.tenantId
|
|
574
|
+
const resolvedOrganizationId = input.organizationId ?? scopeSeed.organizationId
|
|
575
|
+
ensureTenantScope(ctx, resolvedTenantId)
|
|
576
|
+
ensureOrganizationScope(ctx, resolvedOrganizationId)
|
|
571
577
|
const payment = assertFound(
|
|
572
578
|
await findOneWithDecryption(
|
|
573
579
|
em,
|
|
574
580
|
SalesPayment,
|
|
575
581
|
{ id: input.id },
|
|
576
582
|
{ populate: ['order'] },
|
|
577
|
-
{ tenantId:
|
|
583
|
+
{ tenantId: resolvedTenantId, organizationId: resolvedOrganizationId },
|
|
578
584
|
),
|
|
579
585
|
'sales.payments.not_found'
|
|
580
586
|
)
|
|
581
|
-
ensureSameScope(payment,
|
|
587
|
+
ensureSameScope(payment, resolvedOrganizationId, resolvedTenantId)
|
|
582
588
|
const previousOrder = payment.order as SalesOrder | null
|
|
583
589
|
if (input.orderId !== undefined) {
|
|
584
590
|
if (!input.orderId) {
|
|
@@ -588,7 +594,7 @@ const updatePaymentCommand: CommandHandler<
|
|
|
588
594
|
await em.findOne(SalesOrder, { id: input.orderId }),
|
|
589
595
|
'sales.payments.order_not_found'
|
|
590
596
|
)
|
|
591
|
-
ensureSameScope(order,
|
|
597
|
+
ensureSameScope(order, resolvedOrganizationId, resolvedTenantId)
|
|
592
598
|
if (
|
|
593
599
|
order.currencyCode &&
|
|
594
600
|
input.currencyCode &&
|
|
@@ -609,7 +615,7 @@ const updatePaymentCommand: CommandHandler<
|
|
|
609
615
|
await em.findOne(SalesPaymentMethod, { id: input.paymentMethodId }),
|
|
610
616
|
'sales.payments.method_not_found'
|
|
611
617
|
)
|
|
612
|
-
ensureSameScope(method,
|
|
618
|
+
ensureSameScope(method, resolvedOrganizationId, resolvedTenantId)
|
|
613
619
|
payment.paymentMethod = method
|
|
614
620
|
}
|
|
615
621
|
}
|
|
@@ -1106,6 +1106,9 @@
|
|
|
1106
1106
|
"sales.errors.tag_required": "Tag ist erforderlich.",
|
|
1107
1107
|
"sales.errors.tenant_required": "Mandantenkontext ist erforderlich",
|
|
1108
1108
|
"sales.errors.unauthorized": "Nicht autorisiert",
|
|
1109
|
+
"sales.messageObjects.notFound": "Nicht gefunden",
|
|
1110
|
+
"sales.messageObjects.order.title": "Bestellung",
|
|
1111
|
+
"sales.messageObjects.quote.title": "Angebot",
|
|
1109
1112
|
"sales.module.description": "Angebote, Aufträge, Fulfillment, Rechnungsstellung und Zahlungen verbunden mit dem Produktkatalog.",
|
|
1110
1113
|
"sales.module.title": "Vertriebsmanagement",
|
|
1111
1114
|
"sales.nav.channels": "Vertriebskanäle",
|
|
@@ -1106,6 +1106,9 @@
|
|
|
1106
1106
|
"sales.errors.tag_required": "Tag is required.",
|
|
1107
1107
|
"sales.errors.tenant_required": "Tenant context is required",
|
|
1108
1108
|
"sales.errors.unauthorized": "Unauthorized",
|
|
1109
|
+
"sales.messageObjects.notFound": "Not found",
|
|
1110
|
+
"sales.messageObjects.order.title": "Sales order",
|
|
1111
|
+
"sales.messageObjects.quote.title": "Sales quote",
|
|
1109
1112
|
"sales.module.description": "Quotes, orders, fulfillment, invoicing, and payments connected to the product catalog.",
|
|
1110
1113
|
"sales.module.title": "Sales Management",
|
|
1111
1114
|
"sales.nav.channels": "Channels",
|