@open-mercato/core 0.6.2-develop.3467.1.2a1818709d → 0.6.2
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 +1 -1
- package/dist/helpers/integration/queue-runner.js +15 -3
- package/dist/helpers/integration/queue-runner.js.map +2 -2
- package/dist/helpers/integration/queue.js +1 -1
- package/dist/helpers/integration/queue.js.map +2 -2
- package/dist/helpers/integration/salesUi.js +24 -1
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +37 -1
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +36 -2
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +36 -1
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +101 -13
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +32 -14
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +1 -1
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +1 -1
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/backend/users/roleOptions.js +1 -1
- package/dist/modules/auth/backend/users/roleOptions.js.map +2 -2
- package/dist/modules/auth/commands/roles.js +8 -0
- package/dist/modules/auth/commands/roles.js.map +2 -2
- package/dist/modules/auth/commands/users.js +3 -0
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/components/AclEditor.js +53 -26
- package/dist/modules/auth/components/AclEditor.js.map +2 -2
- package/dist/modules/auth/lib/grantChecks.js +97 -2
- package/dist/modules/auth/lib/grantChecks.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +9 -7
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/customers/ai-agents.js +10 -1
- package/dist/modules/customers/ai-agents.js.map +2 -2
- package/dist/modules/customers/ai-tools/settings-pack.js +55 -1
- package/dist/modules/customers/ai-tools/settings-pack.js.map +2 -2
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +13 -5
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +2 -2
- package/dist/modules/customers/lib/personCompanyLinkTable.js +4 -30
- package/dist/modules/customers/lib/personCompanyLinkTable.js.map +2 -2
- package/dist/modules/customers/migrations/Migration20260521175027.js +12 -0
- package/dist/modules/customers/migrations/Migration20260521175027.js.map +7 -0
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +41 -12
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/options.js +2 -0
- package/dist/modules/data_sync/api/options.js.map +2 -2
- package/dist/modules/data_sync/api/run.js +77 -58
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +3 -2
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js +8 -3
- package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
- package/dist/modules/integrations/backend/integrations/[id]/page.js +15 -13
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/integrations/data/validators.js +9 -6
- package/dist/modules/integrations/data/validators.js.map +2 -2
- package/dist/modules/messages/api/route.js +2 -2
- package/dist/modules/messages/api/route.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +42 -2
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +66 -87
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/inboxFilters.js +133 -0
- package/dist/modules/messages/components/inboxFilters.js.map +7 -0
- package/dist/modules/messages/data/validators.js +8 -6
- package/dist/modules/messages/data/validators.js.map +2 -2
- package/dist/modules/progress/api/jobs/route.js +26 -16
- package/dist/modules/progress/api/jobs/route.js.map +2 -2
- package/dist/modules/query_index/di.js +8 -6
- package/dist/modules/query_index/di.js.map +2 -2
- package/dist/modules/query_index/lib/indexer.js +12 -10
- package/dist/modules/query_index/lib/indexer.js.map +2 -2
- package/dist/modules/query_index/subscribers/upsert_one.js +7 -1
- package/dist/modules/query_index/subscribers/upsert_one.js.map +2 -2
- package/dist/modules/sales/api/order-adjustments/route.js.map +2 -2
- package/dist/modules/sales/api/quote-adjustments/route.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +104 -0
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/data/validators.js +20 -1
- package/dist/modules/sales/data/validators.js.map +2 -2
- package/dist/modules/sales/lib/makeSalesLineRoute.js.map +2 -2
- package/dist/modules/sync_excel/api/import/route.js +126 -116
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +1 -0
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +9 -4
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +23 -11
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/jest.config.cjs +4 -1
- package/package.json +15 -16
- package/src/helpers/integration/queue-runner.ts +21 -2
- package/src/helpers/integration/queue.ts +1 -1
- package/src/helpers/integration/salesUi.ts +26 -1
- package/src/modules/auth/api/roles/acl/route.ts +39 -1
- package/src/modules/auth/api/roles/route.ts +38 -2
- package/src/modules/auth/api/users/acl/route.ts +41 -1
- package/src/modules/auth/api/users/route.ts +105 -12
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +35 -13
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +1 -1
- package/src/modules/auth/backend/users/create/page.tsx +1 -1
- package/src/modules/auth/backend/users/roleOptions.ts +2 -1
- package/src/modules/auth/commands/roles.ts +8 -0
- package/src/modules/auth/commands/users.ts +3 -0
- package/src/modules/auth/components/AclEditor.tsx +50 -24
- package/src/modules/auth/lib/grantChecks.ts +116 -2
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -13
- package/src/modules/customers/ai-agents.ts +10 -1
- package/src/modules/customers/ai-tools/settings-pack.ts +62 -1
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +18 -7
- package/src/modules/customers/lib/personCompanyLinkTable.ts +33 -41
- package/src/modules/customers/migrations/Migration20260521175027.ts +39 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +38 -12
- package/src/modules/data_sync/api/options.ts +2 -0
- package/src/modules/data_sync/api/run.ts +80 -61
- package/src/modules/data_sync/backend/data-sync/page.tsx +10 -0
- package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +17 -3
- package/src/modules/data_sync/i18n/de.json +3 -0
- package/src/modules/data_sync/i18n/en.json +3 -0
- package/src/modules/data_sync/i18n/es.json +3 -0
- package/src/modules/data_sync/i18n/pl.json +3 -0
- package/src/modules/data_sync/lib/adapter.ts +9 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +15 -13
- package/src/modules/integrations/data/validators.ts +5 -4
- package/src/modules/messages/api/route.ts +2 -2
- package/src/modules/messages/commands/messages.ts +54 -2
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +75 -90
- package/src/modules/messages/components/inboxFilters.ts +162 -0
- package/src/modules/messages/data/validators.ts +7 -5
- package/src/modules/messages/i18n/de.json +5 -4
- package/src/modules/messages/i18n/en.json +5 -4
- package/src/modules/messages/i18n/es.json +5 -4
- package/src/modules/messages/i18n/pl.json +5 -4
- package/src/modules/progress/api/jobs/route.ts +30 -20
- package/src/modules/query_index/di.ts +9 -7
- package/src/modules/query_index/lib/indexer.ts +13 -11
- package/src/modules/query_index/subscribers/upsert_one.ts +9 -1
- package/src/modules/sales/api/order-adjustments/route.ts +2 -1
- package/src/modules/sales/api/quote-adjustments/route.ts +2 -1
- package/src/modules/sales/commands/documents.ts +116 -0
- package/src/modules/sales/data/validators.ts +38 -0
- package/src/modules/sales/i18n/de.json +2 -0
- package/src/modules/sales/i18n/en.json +2 -0
- package/src/modules/sales/i18n/es.json +2 -0
- package/src/modules/sales/i18n/pl.json +2 -0
- package/src/modules/sales/lib/makeSalesLineRoute.ts +2 -1
- package/src/modules/staff/i18n/de.json +1 -0
- package/src/modules/staff/i18n/en.json +1 -0
- package/src/modules/staff/i18n/es.json +1 -0
- package/src/modules/staff/i18n/pl.json +1 -0
- package/src/modules/sync_excel/api/import/route.ts +141 -131
- package/src/modules/sync_excel/lib/adapters/customers.ts +1 -0
- package/src/modules/translations/components/TranslationManager.tsx +9 -4
- package/src/modules/workflows/lib/activity-executor.ts +4 -3
- package/src/modules/workflows/lib/event-trigger-service.ts +24 -11
- package/tsconfig.json +1 -0
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
"audit_logs.resource_kind.sales.payment": "Payment",
|
|
5
5
|
"audit_logs.resource_kind.sales.shipment": "Shipment",
|
|
6
6
|
"customers~sales.nav.group": "Sales",
|
|
7
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross": "Return adjustment amountGross exceeds the remaining grand total. Reduce the amount or remove existing returns first.",
|
|
8
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet": "Return adjustment amountNet exceeds the remaining grand total. Reduce the amount or remove existing returns first.",
|
|
7
9
|
"sales.audit.channels.create": "Create sales channel",
|
|
8
10
|
"sales.audit.channels.delete": "Delete sales channel",
|
|
9
11
|
"sales.audit.channels.update": "Update sales channel",
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
"audit_logs.resource_kind.sales.payment": "Pago",
|
|
5
5
|
"audit_logs.resource_kind.sales.shipment": "Envío",
|
|
6
6
|
"customers~sales.nav.group": "Ventas",
|
|
7
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross": "El importe bruto del ajuste de devolución supera el total restante. Reduzca el importe o elimine las devoluciones existentes.",
|
|
8
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet": "El importe neto del ajuste de devolución supera el total restante. Reduzca el importe o elimine las devoluciones existentes.",
|
|
7
9
|
"sales.audit.channels.create": "Crear canal de ventas",
|
|
8
10
|
"sales.audit.channels.delete": "Eliminar canal de ventas",
|
|
9
11
|
"sales.audit.channels.update": "Actualizar canal de ventas",
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
"audit_logs.resource_kind.sales.payment": "Płatność",
|
|
5
5
|
"audit_logs.resource_kind.sales.shipment": "Wysyłka",
|
|
6
6
|
"customers~sales.nav.group": "Sprzedaż",
|
|
7
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross": "Kwota brutto korekty zwrotu przekracza pozostałą wartość zamówienia. Zmniejsz kwotę lub usuń istniejące zwroty.",
|
|
8
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet": "Kwota netto korekty zwrotu przekracza pozostałą wartość zamówienia. Zmniejsz kwotę lub usuń istniejące zwroty.",
|
|
7
9
|
"sales.audit.channels.create": "Utwórz kanał sprzedaży",
|
|
8
10
|
"sales.audit.channels.delete": "Usuń kanał sprzedaży",
|
|
9
11
|
"sales.audit.channels.update": "Zaktualizuj kanał sprzedaży",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/core'
|
|
2
3
|
import { makeCrudRoute, type CrudCtx } from '@open-mercato/shared/lib/crud/factory'
|
|
3
4
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
4
5
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
@@ -210,7 +211,7 @@ export function makeSalesLineRoute(config: SalesLineRouteConfig) {
|
|
|
210
211
|
if (query.id) filters.id = { $eq: query.id }
|
|
211
212
|
if (query[parentFkParam]) filters[parentFkColumn] = { $eq: query[parentFkParam] }
|
|
212
213
|
try {
|
|
213
|
-
const em = ctx.container.resolve('em')
|
|
214
|
+
const em = ctx.container.resolve<EntityManager>('em')
|
|
214
215
|
const cfFilters = await buildCustomFieldFiltersFromQuery({
|
|
215
216
|
entityId,
|
|
216
217
|
query,
|
|
@@ -280,6 +280,7 @@
|
|
|
280
280
|
"staff.messageObjects.notFound": "Nicht gefunden",
|
|
281
281
|
"staff.messageObjects.team.title": "Team",
|
|
282
282
|
"staff.messageObjects.teamMember.title": "Teammitglied",
|
|
283
|
+
"staff.messages.leaveRequestApproval": "Urlaubsantrag – Genehmigung",
|
|
283
284
|
"staff.myAvailability.empty.profileRequired": "Erstelle dein Teamprofil, um Verfügbarkeit zu verwalten.",
|
|
284
285
|
"staff.myAvailability.errors.load": "Verfügbarkeit konnte nicht geladen werden.",
|
|
285
286
|
"staff.myAvailability.loading": "Verfügbarkeit wird geladen...",
|
|
@@ -280,6 +280,7 @@
|
|
|
280
280
|
"staff.messageObjects.notFound": "Not found",
|
|
281
281
|
"staff.messageObjects.team.title": "Team",
|
|
282
282
|
"staff.messageObjects.teamMember.title": "Team member",
|
|
283
|
+
"staff.messages.leaveRequestApproval": "Leave request approval",
|
|
283
284
|
"staff.myAvailability.empty.profileRequired": "Create your team member profile to manage availability.",
|
|
284
285
|
"staff.myAvailability.errors.load": "Failed to load availability.",
|
|
285
286
|
"staff.myAvailability.loading": "Loading availability...",
|
|
@@ -280,6 +280,7 @@
|
|
|
280
280
|
"staff.messageObjects.notFound": "No encontrado",
|
|
281
281
|
"staff.messageObjects.team.title": "Equipo",
|
|
282
282
|
"staff.messageObjects.teamMember.title": "Miembro del equipo",
|
|
283
|
+
"staff.messages.leaveRequestApproval": "Solicitud de permiso: aprobación",
|
|
283
284
|
"staff.myAvailability.empty.profileRequired": "Crea tu perfil de miembro para gestionar la disponibilidad.",
|
|
284
285
|
"staff.myAvailability.errors.load": "No se pudo cargar la disponibilidad.",
|
|
285
286
|
"staff.myAvailability.loading": "Cargando disponibilidad...",
|
|
@@ -280,6 +280,7 @@
|
|
|
280
280
|
"staff.messageObjects.notFound": "Nie znaleziono",
|
|
281
281
|
"staff.messageObjects.team.title": "Zespół",
|
|
282
282
|
"staff.messageObjects.teamMember.title": "Członek zespołu",
|
|
283
|
+
"staff.messages.leaveRequestApproval": "Wniosek urlopowy – zatwierdzenie",
|
|
283
284
|
"staff.myAvailability.empty.profileRequired": "Utwórz profil pracownika, aby zarządzać dostępnością.",
|
|
284
285
|
"staff.myAvailability.errors.load": "Nie udało się załadować dostępności.",
|
|
285
286
|
"staff.myAvailability.loading": "Ładowanie dostępności...",
|
|
@@ -46,137 +46,147 @@ export const openApi = {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export async function POST(request: Request) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
existingMapping
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
49
|
+
try {
|
|
50
|
+
const auth = await getAuthFromRequest(request)
|
|
51
|
+
if (!auth?.tenantId) {
|
|
52
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const payload = await readJsonSafe(request)
|
|
56
|
+
const parsedPayload = syncExcelImportRequestSchema.safeParse(payload)
|
|
57
|
+
if (!parsedPayload.success) {
|
|
58
|
+
return NextResponse.json({ error: 'Invalid import payload.' }, { status: 422 })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const container = await createRequestContainer()
|
|
62
|
+
const em = container.resolve('em') as EntityManager
|
|
63
|
+
const syncRunService = container.resolve('dataSyncRunService') as SyncRunService
|
|
64
|
+
const progressService = container.resolve('progressService') as ProgressService
|
|
65
|
+
const credentialsService = container.resolve('integrationCredentialsService') as CredentialsService
|
|
66
|
+
const integrationStateService = container.resolve('integrationStateService') as IntegrationStateService
|
|
67
|
+
const scopeResult = await resolveSyncExcelConcreteScope({ auth, container, request })
|
|
68
|
+
if (!scopeResult.ok) {
|
|
69
|
+
return NextResponse.json({ error: scopeResult.error }, { status: scopeResult.status })
|
|
70
|
+
}
|
|
71
|
+
const { scope } = scopeResult
|
|
72
|
+
|
|
73
|
+
const upload = await findOneWithDecryption(
|
|
74
|
+
em,
|
|
75
|
+
SyncExcelUpload,
|
|
76
|
+
{
|
|
77
|
+
id: parsedPayload.data.uploadId,
|
|
78
|
+
organizationId: scope.organizationId,
|
|
79
|
+
tenantId: scope.tenantId,
|
|
80
|
+
},
|
|
81
|
+
undefined,
|
|
82
|
+
scope,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (!upload) {
|
|
86
|
+
return NextResponse.json({ error: 'Upload preview not found.' }, { status: 404 })
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const attachment = await findOneWithDecryption(
|
|
90
|
+
em,
|
|
91
|
+
Attachment,
|
|
92
|
+
{
|
|
93
|
+
id: upload.attachmentId,
|
|
94
|
+
organizationId: scope.organizationId,
|
|
95
|
+
tenantId: scope.tenantId,
|
|
96
|
+
},
|
|
97
|
+
undefined,
|
|
98
|
+
scope,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
if (!attachment) {
|
|
102
|
+
return NextResponse.json({ error: 'Upload attachment not found.' }, { status: 404 })
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (upload.entityType !== parsedPayload.data.entityType) {
|
|
106
|
+
return NextResponse.json({ error: 'Upload entity type does not match requested import target.' }, { status: 422 })
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (parsedPayload.data.mapping.entityType !== parsedPayload.data.entityType) {
|
|
110
|
+
return NextResponse.json({ error: 'Mapping entity type does not match requested import target.' }, { status: 422 })
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const overlap = await syncRunService.findRunningOverlap('sync_excel', parsedPayload.data.entityType, 'import', scope)
|
|
114
|
+
if (overlap) {
|
|
115
|
+
return NextResponse.json({ error: 'A sync_excel import is already in progress for this entity type.' }, { status: 409 })
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const existingMapping = await findOneWithDecryption(
|
|
119
|
+
em,
|
|
120
|
+
SyncMapping,
|
|
121
|
+
{
|
|
122
|
+
integrationId: 'sync_excel',
|
|
123
|
+
entityType: parsedPayload.data.entityType,
|
|
124
|
+
organizationId: scope.organizationId,
|
|
125
|
+
tenantId: scope.tenantId,
|
|
126
|
+
},
|
|
127
|
+
undefined,
|
|
128
|
+
scope,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if (existingMapping) {
|
|
132
|
+
existingMapping.mapping = parsedPayload.data.mapping
|
|
133
|
+
} else {
|
|
134
|
+
em.persist(em.create(SyncMapping, {
|
|
135
|
+
integrationId: 'sync_excel',
|
|
136
|
+
entityType: parsedPayload.data.entityType,
|
|
137
|
+
mapping: parsedPayload.data.mapping,
|
|
138
|
+
organizationId: scope.organizationId,
|
|
139
|
+
tenantId: scope.tenantId,
|
|
140
|
+
}))
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
await credentialsService.save('sync_excel', {}, scope)
|
|
144
|
+
await integrationStateService.upsert('sync_excel', { isEnabled: true }, scope)
|
|
145
|
+
await em.flush()
|
|
146
|
+
|
|
147
|
+
const { run, progressJob } = await startDataSyncRun({
|
|
148
|
+
syncRunService,
|
|
149
|
+
progressService,
|
|
150
|
+
scope: {
|
|
151
|
+
...scope,
|
|
152
|
+
userId: auth.sub,
|
|
153
|
+
},
|
|
154
|
+
input: {
|
|
155
|
+
integrationId: 'sync_excel',
|
|
156
|
+
entityType: parsedPayload.data.entityType,
|
|
157
|
+
direction: 'import',
|
|
158
|
+
cursor: createCursor(upload.id, 0),
|
|
159
|
+
triggeredBy: auth.sub,
|
|
160
|
+
batchSize: parsedPayload.data.batchSize ?? 100,
|
|
161
|
+
progressJob: {
|
|
162
|
+
jobType: 'sync_excel:import',
|
|
163
|
+
name: `CSV import — ${parsedPayload.data.entityType}`,
|
|
164
|
+
description: upload.filename,
|
|
165
|
+
meta: {
|
|
166
|
+
integrationId: 'sync_excel',
|
|
167
|
+
uploadId: upload.id,
|
|
168
|
+
hiddenFromTopBar: false,
|
|
169
|
+
},
|
|
168
170
|
},
|
|
169
171
|
},
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
status:
|
|
181
|
-
})
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
upload.syncRunId = run.id
|
|
175
|
+
upload.status = 'importing'
|
|
176
|
+
await em.flush()
|
|
177
|
+
|
|
178
|
+
return NextResponse.json(syncExcelImportResponseSchema.parse({
|
|
179
|
+
runId: run.id,
|
|
180
|
+
progressJobId: progressJob?.id ?? null,
|
|
181
|
+
status: run.status,
|
|
182
|
+
}), { status: 201 })
|
|
183
|
+
} catch (error) {
|
|
184
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
185
|
+
const stack = error instanceof Error ? error.stack : undefined
|
|
186
|
+
console.error('[sync_excel.import] unhandled error', { message, stack })
|
|
187
|
+
return NextResponse.json(
|
|
188
|
+
{ error: 'Failed to start sync_excel import.', message, stack },
|
|
189
|
+
{ status: 500 },
|
|
190
|
+
)
|
|
191
|
+
}
|
|
182
192
|
}
|
|
@@ -993,6 +993,7 @@ async function processRow(params: {
|
|
|
993
993
|
|
|
994
994
|
export const syncExcelCustomersAdapter: DataSyncAdapter = {
|
|
995
995
|
providerKey: 'excel',
|
|
996
|
+
runMode: 'provider',
|
|
996
997
|
operationalTelemetry: true,
|
|
997
998
|
direction: 'import',
|
|
998
999
|
supportedEntities: ['customers.person'],
|
|
@@ -69,6 +69,7 @@ export function TranslationManager({
|
|
|
69
69
|
const [editedTranslations, setEditedTranslations] = React.useState<Record<string, Record<string, string>>>({})
|
|
70
70
|
const editedTranslationsRef = React.useRef<Record<string, Record<string, string>>>({})
|
|
71
71
|
const [hasUserEdited, setHasUserEdited] = React.useState(false)
|
|
72
|
+
const hasUserEditedRef = React.useRef(false)
|
|
72
73
|
|
|
73
74
|
const entityType = isEmbedded ? (propEntityType ?? '') : selectedEntityType
|
|
74
75
|
const recordId = isEmbedded ? (propRecordId ?? '') : selectedRecordId
|
|
@@ -191,11 +192,11 @@ export function TranslationManager({
|
|
|
191
192
|
|
|
192
193
|
React.useEffect(() => {
|
|
193
194
|
const sig = translationSignature
|
|
194
|
-
if (sig === lastTranslationSignatureRef.current &&
|
|
195
|
+
if (sig === lastTranslationSignatureRef.current && hasUserEditedRef.current) return
|
|
195
196
|
lastTranslationSignatureRef.current = sig
|
|
196
197
|
|
|
197
198
|
if (!translationData?.translations) {
|
|
198
|
-
if (!
|
|
199
|
+
if (!hasUserEditedRef.current) {
|
|
199
200
|
editedTranslationsRef.current = {}
|
|
200
201
|
setEditedTranslations({})
|
|
201
202
|
}
|
|
@@ -210,11 +211,11 @@ export function TranslationManager({
|
|
|
210
211
|
parsed[locale][key] = typeof val === 'string' ? val : ''
|
|
211
212
|
}
|
|
212
213
|
}
|
|
213
|
-
if (!
|
|
214
|
+
if (!hasUserEditedRef.current) {
|
|
214
215
|
editedTranslationsRef.current = parsed
|
|
215
216
|
setEditedTranslations(parsed)
|
|
216
217
|
}
|
|
217
|
-
}, [translationSignature, translationData
|
|
218
|
+
}, [translationSignature, translationData])
|
|
218
219
|
|
|
219
220
|
const mutation = useMutation({
|
|
220
221
|
mutationFn: async () => {
|
|
@@ -252,6 +253,7 @@ export function TranslationManager({
|
|
|
252
253
|
},
|
|
253
254
|
onSuccess: () => {
|
|
254
255
|
flash(t('translations.manager.flash.saved', 'Translations saved'), 'success')
|
|
256
|
+
hasUserEditedRef.current = false
|
|
255
257
|
setHasUserEdited(false)
|
|
256
258
|
void refetchTranslation()
|
|
257
259
|
},
|
|
@@ -262,6 +264,7 @@ export function TranslationManager({
|
|
|
262
264
|
})
|
|
263
265
|
|
|
264
266
|
const updateFieldValue = (locale: string, fieldKey: string, value: string) => {
|
|
267
|
+
hasUserEditedRef.current = true
|
|
265
268
|
setHasUserEdited(true)
|
|
266
269
|
const next = {
|
|
267
270
|
...editedTranslationsRef.current,
|
|
@@ -288,6 +291,7 @@ export function TranslationManager({
|
|
|
288
291
|
value={selectedRecordId}
|
|
289
292
|
onChange={(next) => {
|
|
290
293
|
setSelectedRecordId(next)
|
|
294
|
+
hasUserEditedRef.current = false
|
|
291
295
|
setHasUserEdited(false)
|
|
292
296
|
}}
|
|
293
297
|
placeholder={t('translations.manager.searchRecords', 'Search records...')}
|
|
@@ -482,6 +486,7 @@ export function TranslationManager({
|
|
|
482
486
|
onChange={(next) => {
|
|
483
487
|
setSelectedEntityType(next)
|
|
484
488
|
setSelectedRecordId('')
|
|
489
|
+
hasUserEditedRef.current = false
|
|
485
490
|
setHasUserEdited(false)
|
|
486
491
|
}}
|
|
487
492
|
placeholder={t('translations.manager.placeholder', 'Select an entity')}
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { EntityManager } from '@mikro-orm/core'
|
|
14
|
+
import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
|
|
14
15
|
import type { AwilixContainer } from 'awilix'
|
|
15
16
|
import { WorkflowInstance } from '../data/entities'
|
|
16
17
|
import { createModuleQueue, Queue } from '@open-mercato/queue'
|
|
@@ -406,7 +407,7 @@ export async function executeSendEmail(
|
|
|
406
407
|
|
|
407
408
|
// Check if email service is available in container
|
|
408
409
|
try {
|
|
409
|
-
const emailService = container.resolve('emailService')
|
|
410
|
+
const emailService = container.resolve<{ send: (input: unknown) => Promise<unknown> | unknown }>('emailService')
|
|
410
411
|
if (emailService && typeof emailService.send === 'function') {
|
|
411
412
|
await emailService.send({
|
|
412
413
|
to,
|
|
@@ -441,7 +442,7 @@ export async function executeEmitEvent(
|
|
|
441
442
|
}
|
|
442
443
|
|
|
443
444
|
// Get event bus from container
|
|
444
|
-
const eventBus = container.resolve('eventBus')
|
|
445
|
+
const eventBus = container.resolve<{ emitEvent: (event: string, payload: unknown, options?: unknown) => Promise<unknown> | unknown }>('eventBus')
|
|
445
446
|
|
|
446
447
|
if (!eventBus || typeof eventBus.emitEvent !== 'function') {
|
|
447
448
|
throw new Error('Event bus not available in container')
|
|
@@ -789,7 +790,7 @@ export async function executeCallApi(
|
|
|
789
790
|
const { withOnetimeApiKey } = await import('../../api_keys/services/apiKeyService')
|
|
790
791
|
|
|
791
792
|
// 4. Get EntityManager from container (for correct type)
|
|
792
|
-
const apiKeyEm = container.resolve('em')
|
|
793
|
+
const apiKeyEm = container.resolve<PostgreSqlEntityManager>('em')
|
|
793
794
|
|
|
794
795
|
// 5. Resolve the roles that the one-time API key will inherit.
|
|
795
796
|
//
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { EntityManager } from '@mikro-orm/core'
|
|
9
|
+
import type { EntityManager as PostgreSqlEntityManager } from '@mikro-orm/postgresql'
|
|
9
10
|
import type { AwilixContainer } from 'awilix'
|
|
10
11
|
import type { CacheService } from '@open-mercato/cache'
|
|
11
12
|
import { matchEventPattern } from '@open-mercato/shared/lib/events/patterns'
|
|
13
|
+
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
14
|
+
import { testLinearRegex } from '@open-mercato/shared/lib/regex/linear'
|
|
12
15
|
import {
|
|
13
16
|
WorkflowEventTrigger,
|
|
14
17
|
WorkflowDefinition,
|
|
@@ -257,11 +260,12 @@ function evaluateCondition(condition: TriggerFilterCondition, payload: Record<st
|
|
|
257
260
|
if (typeof value !== 'string' || typeof expected !== 'string') return false
|
|
258
261
|
if (value.length > MAX_WORKFLOW_REGEX_INPUT_LENGTH) return false
|
|
259
262
|
if (!isSafeWorkflowRegexPattern(expected)) return false
|
|
260
|
-
|
|
261
|
-
const
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
{
|
|
264
|
+
const result = testLinearRegex(expected, value, {
|
|
265
|
+
maxPatternLength: MAX_WORKFLOW_REGEX_PATTERN_LENGTH,
|
|
266
|
+
maxInputLength: MAX_WORKFLOW_REGEX_INPUT_LENGTH,
|
|
267
|
+
})
|
|
268
|
+
return result.ok ? result.matched : false
|
|
265
269
|
}
|
|
266
270
|
|
|
267
271
|
default:
|
|
@@ -325,7 +329,9 @@ async function loadLegacyTriggers(
|
|
|
325
329
|
tenantId: string,
|
|
326
330
|
organizationId: string
|
|
327
331
|
): Promise<UnifiedTrigger[]> {
|
|
328
|
-
const
|
|
332
|
+
const postgresEm = em as unknown as PostgreSqlEntityManager
|
|
333
|
+
const legacyTriggers = await findWithDecryption(
|
|
334
|
+
postgresEm,
|
|
329
335
|
WorkflowEventTrigger,
|
|
330
336
|
{
|
|
331
337
|
tenantId,
|
|
@@ -335,16 +341,19 @@ async function loadLegacyTriggers(
|
|
|
335
341
|
},
|
|
336
342
|
{
|
|
337
343
|
orderBy: { priority: 'DESC', createdAt: 'ASC' },
|
|
338
|
-
}
|
|
344
|
+
},
|
|
345
|
+
{ tenantId, organizationId },
|
|
339
346
|
)
|
|
340
347
|
|
|
341
348
|
// Get definitions for these triggers to get workflowId
|
|
342
349
|
const definitionIds = [...new Set(legacyTriggers.map(t => t.workflowDefinitionId))]
|
|
343
|
-
const definitions = definitionIds.length > 0 ? await
|
|
350
|
+
const definitions = definitionIds.length > 0 ? await findWithDecryption(postgresEm, WorkflowDefinition, {
|
|
344
351
|
id: { $in: definitionIds },
|
|
352
|
+
tenantId,
|
|
353
|
+
organizationId,
|
|
345
354
|
enabled: true,
|
|
346
355
|
deletedAt: null,
|
|
347
|
-
}) : []
|
|
356
|
+
}, {}, { tenantId, organizationId }) : []
|
|
348
357
|
const definitionMap = new Map(definitions.map(d => [d.id, d]))
|
|
349
358
|
|
|
350
359
|
return legacyTriggers
|
|
@@ -379,15 +388,19 @@ async function loadEmbeddedTriggers(
|
|
|
379
388
|
tenantId: string,
|
|
380
389
|
organizationId: string
|
|
381
390
|
): Promise<UnifiedTrigger[]> {
|
|
391
|
+
const postgresEm = em as unknown as PostgreSqlEntityManager
|
|
382
392
|
// Load all enabled definitions that may have triggers
|
|
383
|
-
const definitions = await
|
|
393
|
+
const definitions = await findWithDecryption(
|
|
394
|
+
postgresEm,
|
|
384
395
|
WorkflowDefinition,
|
|
385
396
|
{
|
|
386
397
|
tenantId,
|
|
387
398
|
organizationId,
|
|
388
399
|
enabled: true,
|
|
389
400
|
deletedAt: null,
|
|
390
|
-
}
|
|
401
|
+
},
|
|
402
|
+
{},
|
|
403
|
+
{ tenantId, organizationId },
|
|
391
404
|
)
|
|
392
405
|
|
|
393
406
|
const triggers: UnifiedTrigger[] = []
|