@open-mercato/core 0.6.2-develop.3461.1.605f31c2c9 → 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/frontend/login.js +35 -0
- package/dist/modules/auth/frontend/login.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/business_rules/lib/rule-evaluator.js +3 -3
- package/dist/modules/business_rules/lib/rule-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 +70 -89
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.js +8 -6
- package/dist/modules/messages/components/defaults/DefaultMessageListItem.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/components/messageListLabels.js +14 -0
- package/dist/modules/messages/components/messageListLabels.js.map +7 -0
- package/dist/modules/messages/components/useMessagesInboxBulkActions.js +47 -23
- package/dist/modules/messages/components/useMessagesInboxBulkActions.js.map +2 -2
- 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/frontend/login.tsx +40 -0
- package/src/modules/auth/lib/grantChecks.ts +116 -2
- package/src/modules/business_rules/lib/expression-evaluator.ts +9 -13
- package/src/modules/business_rules/lib/rule-evaluator.ts +3 -3
- 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 +80 -92
- package/src/modules/messages/components/defaults/DefaultMessageListItem.tsx +9 -5
- package/src/modules/messages/components/inboxFilters.ts +162 -0
- package/src/modules/messages/components/messageListLabels.ts +29 -0
- package/src/modules/messages/components/useMessagesInboxBulkActions.ts +58 -26
- package/src/modules/messages/data/validators.ts +7 -5
- package/src/modules/messages/i18n/de.json +7 -4
- package/src/modules/messages/i18n/en.json +7 -4
- package/src/modules/messages/i18n/es.json +7 -4
- package/src/modules/messages/i18n/pl.json +7 -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
|
@@ -131,12 +131,13 @@
|
|
|
131
131
|
"messages.externalName": "Nombre externo",
|
|
132
132
|
"messages.fields.type": "Tipo de mensaje",
|
|
133
133
|
"messages.filters.all": "Todos",
|
|
134
|
-
"messages.filters.hasActions": "
|
|
135
|
-
"messages.filters.hasAttachments": "
|
|
136
|
-
"messages.filters.hasObjects": "
|
|
134
|
+
"messages.filters.hasActions": "Tiene acciones",
|
|
135
|
+
"messages.filters.hasAttachments": "Tiene adjuntos",
|
|
136
|
+
"messages.filters.hasObjects": "Tiene objetos",
|
|
137
137
|
"messages.filters.sender": "Remitente",
|
|
138
|
+
"messages.filters.senderEmpty": "Escribe para buscar usuarios",
|
|
138
139
|
"messages.filters.since": "Enviado después de",
|
|
139
|
-
"messages.filters.sincePlaceholder": "YYYY-MM-
|
|
140
|
+
"messages.filters.sincePlaceholder": "YYYY-MM-DD",
|
|
140
141
|
"messages.filters.status": "Estado",
|
|
141
142
|
"messages.filters.type": "Tipo",
|
|
142
143
|
"messages.flash.actionSuccess": "Acción completada.",
|
|
@@ -159,6 +160,8 @@
|
|
|
159
160
|
"messages.forwardNote": "Nota opcional",
|
|
160
161
|
"messages.includeAttachments": "Incluir adjuntos",
|
|
161
162
|
"messages.includeAttachmentsHint": "Conservar adjuntos del mensaje original.",
|
|
163
|
+
"messages.list.noRecipient": "(Sin destinatario)",
|
|
164
|
+
"messages.list.noSubject": "(Sin asunto)",
|
|
162
165
|
"messages.loading.attachments": "Cargando adjuntos...",
|
|
163
166
|
"messages.loading.detail": "Cargando mensaje...",
|
|
164
167
|
"messages.loading.objectTypes": "Cargando tipos de objeto...",
|
|
@@ -131,12 +131,13 @@
|
|
|
131
131
|
"messages.externalName": "Nazwa zewnętrzna",
|
|
132
132
|
"messages.fields.type": "Typ wiadomości",
|
|
133
133
|
"messages.filters.all": "Wszystkie",
|
|
134
|
-
"messages.filters.hasActions": "
|
|
135
|
-
"messages.filters.hasAttachments": "
|
|
136
|
-
"messages.filters.hasObjects": "
|
|
134
|
+
"messages.filters.hasActions": "Ma akcje",
|
|
135
|
+
"messages.filters.hasAttachments": "Ma załączniki",
|
|
136
|
+
"messages.filters.hasObjects": "Ma obiekty",
|
|
137
137
|
"messages.filters.sender": "Nadawca",
|
|
138
|
+
"messages.filters.senderEmpty": "Wpisz, aby wyszukać użytkowników",
|
|
138
139
|
"messages.filters.since": "Wysłane po",
|
|
139
|
-
"messages.filters.sincePlaceholder": "
|
|
140
|
+
"messages.filters.sincePlaceholder": "RRRR-MM-DD",
|
|
140
141
|
"messages.filters.status": "Status",
|
|
141
142
|
"messages.filters.type": "Typ",
|
|
142
143
|
"messages.flash.actionSuccess": "Akcja wykonana.",
|
|
@@ -159,6 +160,8 @@
|
|
|
159
160
|
"messages.forwardNote": "Notatka opcjonalna",
|
|
160
161
|
"messages.includeAttachments": "Dołącz załączniki",
|
|
161
162
|
"messages.includeAttachmentsHint": "Przenieś załączniki z oryginalnej wiadomości.",
|
|
163
|
+
"messages.list.noRecipient": "(Brak odbiorcy)",
|
|
164
|
+
"messages.list.noSubject": "(Brak tematu)",
|
|
162
165
|
"messages.loading.attachments": "Ładowanie załączników...",
|
|
163
166
|
"messages.loading.detail": "Ładowanie wiadomości...",
|
|
164
167
|
"messages.loading.objectTypes": "Ładowanie typów obiektów...",
|
|
@@ -138,27 +138,37 @@ export async function GET(req: Request) {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
export async function POST(req: Request) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
try {
|
|
142
|
+
const auth = await getAuthFromRequest(req)
|
|
143
|
+
if (!auth || !auth.tenantId) {
|
|
144
|
+
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const body = await req.json()
|
|
148
|
+
const parsed = createProgressJobSchema.safeParse(body)
|
|
149
|
+
if (!parsed.success) {
|
|
150
|
+
return NextResponse.json({ error: 'Invalid input', details: parsed.error.flatten() }, { status: 400 })
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const container = await createRequestContainer()
|
|
154
|
+
const progressService = container.resolve('progressService') as import('../../lib/progressService').ProgressService
|
|
155
|
+
|
|
156
|
+
const job = await progressService.createJob(parsed.data, {
|
|
157
|
+
tenantId: auth.tenantId,
|
|
158
|
+
organizationId: auth.orgId,
|
|
159
|
+
userId: auth.sub,
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
return NextResponse.json({ id: job.id }, { status: 201 })
|
|
163
|
+
} catch (error) {
|
|
164
|
+
const message = error instanceof Error ? error.message : String(error)
|
|
165
|
+
const stack = error instanceof Error ? error.stack : undefined
|
|
166
|
+
console.error('[progress.jobs.create] unhandled error', { message, stack })
|
|
167
|
+
return NextResponse.json(
|
|
168
|
+
{ error: 'Failed to create progress job.', message, stack },
|
|
169
|
+
{ status: 500 },
|
|
170
|
+
)
|
|
150
171
|
}
|
|
151
|
-
|
|
152
|
-
const container = await createRequestContainer()
|
|
153
|
-
const progressService = container.resolve('progressService') as import('../../lib/progressService').ProgressService
|
|
154
|
-
|
|
155
|
-
const job = await progressService.createJob(parsed.data, {
|
|
156
|
-
tenantId: auth.tenantId,
|
|
157
|
-
organizationId: auth.orgId,
|
|
158
|
-
userId: auth.sub,
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
return NextResponse.json({ id: job.id }, { status: 201 })
|
|
162
172
|
}
|
|
163
173
|
|
|
164
174
|
const jobListItemSchema = z.object({
|
|
@@ -66,8 +66,8 @@ export function register(container: AppContainer) {
|
|
|
66
66
|
const makeUpsertHandler = (entityType: string) => async (payload: any, ctx: any) => {
|
|
67
67
|
try {
|
|
68
68
|
const em = ctx.resolve('em')
|
|
69
|
-
let orgId = payload?.organizationId || payload?.orgId || null
|
|
70
|
-
let tenantId = payload?.tenantId || null
|
|
69
|
+
let orgId = payload?.organizationId || payload?.orgId || ctx?.organizationId || null
|
|
70
|
+
let tenantId = payload?.tenantId || ctx?.tenantId || null
|
|
71
71
|
const id = String(payload?.id || payload?.recordId || '')
|
|
72
72
|
if (!id) return
|
|
73
73
|
if (!orgId || !tenantId) {
|
|
@@ -119,24 +119,26 @@ export function register(container: AppContainer) {
|
|
|
119
119
|
const makeDeleteHandler = (entityType: string) => async (payload: any, ctx: any) => {
|
|
120
120
|
try {
|
|
121
121
|
const em = ctx.resolve('em')
|
|
122
|
-
let orgId = payload?.organizationId || payload?.orgId || null
|
|
122
|
+
let orgId = payload?.organizationId || payload?.orgId || ctx?.organizationId || null
|
|
123
|
+
let tenantId = payload?.tenantId || ctx?.tenantId || null
|
|
123
124
|
const id = String(payload?.id || payload?.recordId || '')
|
|
124
125
|
if (!id) return
|
|
125
|
-
if (!orgId) {
|
|
126
|
+
if (!orgId || !tenantId) {
|
|
126
127
|
try {
|
|
127
128
|
const db = (em as any).getKysely()
|
|
128
129
|
const table = resolveEntityTableName(em, entityType)
|
|
129
130
|
const row = await db
|
|
130
131
|
.selectFrom(table as any)
|
|
131
|
-
.select(['organization_id' as any])
|
|
132
|
+
.select(['organization_id' as any, 'tenant_id' as any])
|
|
132
133
|
.where('id' as any, '=', id)
|
|
133
|
-
.executeTakeFirst() as { organization_id: string | null } | undefined
|
|
134
|
+
.executeTakeFirst() as { organization_id: string | null; tenant_id: string | null } | undefined
|
|
134
135
|
orgId = row?.organization_id ?? orgId
|
|
136
|
+
tenantId = row?.tenant_id ?? tenantId
|
|
135
137
|
} catch {}
|
|
136
138
|
}
|
|
137
139
|
try {
|
|
138
140
|
const bus = ctx.resolve('eventBus') as any
|
|
139
|
-
await bus.emitEvent('query_index.delete_one', { entityType, recordId: id, organizationId: orgId })
|
|
141
|
+
await bus.emitEvent('query_index.delete_one', { entityType, recordId: id, organizationId: orgId, tenantId })
|
|
140
142
|
} catch {}
|
|
141
143
|
} catch {}
|
|
142
144
|
}
|
|
@@ -158,7 +158,7 @@ function scopeEntityIndexes<QB extends { where: (...args: any[]) => QB }>(
|
|
|
158
158
|
|
|
159
159
|
export async function upsertIndexRow(
|
|
160
160
|
em: EntityManager,
|
|
161
|
-
args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null }
|
|
161
|
+
args: { entityType: string; recordId: string; organizationId?: string | null; tenantId?: string | null; searchTokenDoc?: Record<string, unknown> | null }
|
|
162
162
|
): Promise<UpsertIndexResult> {
|
|
163
163
|
const db = (em as any).getKysely()
|
|
164
164
|
|
|
@@ -234,21 +234,23 @@ export async function upsertIndexRow(
|
|
|
234
234
|
const created = !existed
|
|
235
235
|
const revived = existed && wasDeleted
|
|
236
236
|
try {
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
237
|
+
const tokenDoc = args.searchTokenDoc ?? (() => {
|
|
238
|
+
const encryption = resolveTenantEncryptionService(em as any)
|
|
239
|
+
const dekKeyCache = new Map<string | null, string | null>()
|
|
240
|
+
return decryptIndexDocForSearch(
|
|
241
|
+
args.entityType,
|
|
242
|
+
doc,
|
|
243
|
+
{ tenantId: args.tenantId ?? null, organizationId: args.organizationId ?? null },
|
|
244
|
+
encryption,
|
|
245
|
+
dekKeyCache,
|
|
246
|
+
)
|
|
247
|
+
})()
|
|
246
248
|
await replaceSearchTokensForRecord(db, {
|
|
247
249
|
entityType: args.entityType,
|
|
248
250
|
recordId: args.recordId,
|
|
249
251
|
organizationId: args.organizationId ?? null,
|
|
250
252
|
tenantId: args.tenantId ?? null,
|
|
251
|
-
doc: tokenDoc,
|
|
253
|
+
doc: await tokenDoc,
|
|
252
254
|
})
|
|
253
255
|
} catch {}
|
|
254
256
|
return { doc, existed, wasDeleted, created, revived }
|
|
@@ -28,7 +28,15 @@ export default async function handle(payload: any, ctx: { resolve: <T=any>(name:
|
|
|
28
28
|
organizationId = resolvedScope.organizationId
|
|
29
29
|
tenantId = resolvedScope.tenantId
|
|
30
30
|
|
|
31
|
-
const result = await upsertIndexRow(em, {
|
|
31
|
+
const result = await upsertIndexRow(em, {
|
|
32
|
+
entityType,
|
|
33
|
+
recordId,
|
|
34
|
+
organizationId,
|
|
35
|
+
tenantId,
|
|
36
|
+
searchTokenDoc: typeof payload?.searchTokenDoc === 'object' && payload.searchTokenDoc && !Array.isArray(payload.searchTokenDoc)
|
|
37
|
+
? payload.searchTokenDoc
|
|
38
|
+
: null,
|
|
39
|
+
})
|
|
32
40
|
if (!suppressCoverage) {
|
|
33
41
|
const doc = result.doc
|
|
34
42
|
const isActive = !!doc && (doc.deleted_at == null || doc.deleted_at === null)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/core'
|
|
2
3
|
import { makeCrudRoute } 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'
|
|
@@ -85,7 +86,7 @@ const crud = makeCrudRoute({
|
|
|
85
86
|
const filters: Record<string, unknown> = {}
|
|
86
87
|
if (query.orderId) filters.order_id = { $eq: query.orderId }
|
|
87
88
|
try {
|
|
88
|
-
const em = ctx.container.resolve('em')
|
|
89
|
+
const em = ctx.container.resolve<EntityManager>('em')
|
|
89
90
|
const cfFilters = await buildCustomFieldFiltersFromQuery({
|
|
90
91
|
entityId: E.sales.sales_order_adjustment,
|
|
91
92
|
query,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
|
+
import type { EntityManager } from '@mikro-orm/core'
|
|
2
3
|
import { makeCrudRoute } 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'
|
|
@@ -82,7 +83,7 @@ const crud = makeCrudRoute({
|
|
|
82
83
|
const filters: Record<string, unknown> = {}
|
|
83
84
|
if (query.quoteId) filters.quote_id = { $eq: query.quoteId }
|
|
84
85
|
try {
|
|
85
|
-
const em = ctx.container.resolve('em')
|
|
86
|
+
const em = ctx.container.resolve<EntityManager>('em')
|
|
86
87
|
const cfFilters = await buildCustomFieldFiltersFromQuery({
|
|
87
88
|
entityId: E.sales.sales_quote_adjustment,
|
|
88
89
|
query,
|
|
@@ -67,6 +67,9 @@ import {
|
|
|
67
67
|
} from "../../customers/data/entities";
|
|
68
68
|
import {
|
|
69
69
|
enforceAdjustmentSign,
|
|
70
|
+
validateReturnAdjustmentWithinRemaining,
|
|
71
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE,
|
|
72
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_NET_MESSAGE,
|
|
70
73
|
quoteCreateSchema,
|
|
71
74
|
quoteLineCreateSchema,
|
|
72
75
|
quoteAdjustmentCreateSchema,
|
|
@@ -7384,6 +7387,63 @@ const orderAdjustmentUpsertCommand: CommandHandler<
|
|
|
7384
7387
|
shippingMethodCode: order.shippingMethodCode ?? null,
|
|
7385
7388
|
paymentMethodCode: order.paymentMethodCode ?? null,
|
|
7386
7389
|
});
|
|
7390
|
+
const effectiveAdjustment = nextAdjustments.find(
|
|
7391
|
+
(adj) => adj.id === adjustmentId,
|
|
7392
|
+
);
|
|
7393
|
+
if (effectiveAdjustment?.kind === "return") {
|
|
7394
|
+
const baselineAdjustments = nextAdjustments.filter(
|
|
7395
|
+
(adj) => adj.id !== adjustmentId,
|
|
7396
|
+
);
|
|
7397
|
+
const baselineCalculation =
|
|
7398
|
+
await salesCalculationService.calculateDocumentTotals({
|
|
7399
|
+
documentKind: "order",
|
|
7400
|
+
lines: calcLines,
|
|
7401
|
+
adjustments: baselineAdjustments,
|
|
7402
|
+
context: calculationContext,
|
|
7403
|
+
existingTotals: resolveExistingPaymentTotals(order),
|
|
7404
|
+
});
|
|
7405
|
+
const issues = validateReturnAdjustmentWithinRemaining({
|
|
7406
|
+
kind: "return",
|
|
7407
|
+
amountNet:
|
|
7408
|
+
effectiveAdjustment.amountNet ?? effectiveAdjustment.amountGross ?? 0,
|
|
7409
|
+
amountGross:
|
|
7410
|
+
effectiveAdjustment.amountGross ?? effectiveAdjustment.amountNet ?? 0,
|
|
7411
|
+
remainingNet: Number(
|
|
7412
|
+
baselineCalculation.totals?.grandTotalNetAmount ?? 0,
|
|
7413
|
+
),
|
|
7414
|
+
remainingGross: Number(
|
|
7415
|
+
baselineCalculation.totals?.grandTotalGrossAmount ?? 0,
|
|
7416
|
+
),
|
|
7417
|
+
});
|
|
7418
|
+
if (issues.length > 0) {
|
|
7419
|
+
const { translate } = await resolveTranslations();
|
|
7420
|
+
const grossIssue = issues.find((issue) => issue.path === "amountGross");
|
|
7421
|
+
const netIssue = issues.find((issue) => issue.path === "amountNet");
|
|
7422
|
+
const fieldErrors: Record<string, string> = {};
|
|
7423
|
+
if (grossIssue) {
|
|
7424
|
+
fieldErrors.amountGross = translate(
|
|
7425
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross",
|
|
7426
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE,
|
|
7427
|
+
);
|
|
7428
|
+
}
|
|
7429
|
+
if (netIssue) {
|
|
7430
|
+
fieldErrors.amountNet = translate(
|
|
7431
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet",
|
|
7432
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_NET_MESSAGE,
|
|
7433
|
+
);
|
|
7434
|
+
}
|
|
7435
|
+
throw new CrudHttpError(400, {
|
|
7436
|
+
error:
|
|
7437
|
+
fieldErrors.amountGross ??
|
|
7438
|
+
fieldErrors.amountNet ??
|
|
7439
|
+
translate(
|
|
7440
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross",
|
|
7441
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE,
|
|
7442
|
+
),
|
|
7443
|
+
fieldErrors,
|
|
7444
|
+
});
|
|
7445
|
+
}
|
|
7446
|
+
}
|
|
7387
7447
|
const calculation = await salesCalculationService.calculateDocumentTotals({
|
|
7388
7448
|
documentKind: "order",
|
|
7389
7449
|
lines: calcLines,
|
|
@@ -7766,6 +7826,62 @@ const quoteAdjustmentUpsertCommand: CommandHandler<
|
|
|
7766
7826
|
shippingMethodCode: quote.shippingMethodCode ?? null,
|
|
7767
7827
|
paymentMethodCode: quote.paymentMethodCode ?? null,
|
|
7768
7828
|
});
|
|
7829
|
+
const effectiveAdjustment = nextAdjustments.find(
|
|
7830
|
+
(adj) => adj.id === adjustmentId,
|
|
7831
|
+
);
|
|
7832
|
+
if (effectiveAdjustment?.kind === "return") {
|
|
7833
|
+
const baselineAdjustments = nextAdjustments.filter(
|
|
7834
|
+
(adj) => adj.id !== adjustmentId,
|
|
7835
|
+
);
|
|
7836
|
+
const baselineCalculation =
|
|
7837
|
+
await salesCalculationService.calculateDocumentTotals({
|
|
7838
|
+
documentKind: "quote",
|
|
7839
|
+
lines: calcLines,
|
|
7840
|
+
adjustments: baselineAdjustments,
|
|
7841
|
+
context: calculationContext,
|
|
7842
|
+
});
|
|
7843
|
+
const issues = validateReturnAdjustmentWithinRemaining({
|
|
7844
|
+
kind: "return",
|
|
7845
|
+
amountNet:
|
|
7846
|
+
effectiveAdjustment.amountNet ?? effectiveAdjustment.amountGross ?? 0,
|
|
7847
|
+
amountGross:
|
|
7848
|
+
effectiveAdjustment.amountGross ?? effectiveAdjustment.amountNet ?? 0,
|
|
7849
|
+
remainingNet: Number(
|
|
7850
|
+
baselineCalculation.totals?.grandTotalNetAmount ?? 0,
|
|
7851
|
+
),
|
|
7852
|
+
remainingGross: Number(
|
|
7853
|
+
baselineCalculation.totals?.grandTotalGrossAmount ?? 0,
|
|
7854
|
+
),
|
|
7855
|
+
});
|
|
7856
|
+
if (issues.length > 0) {
|
|
7857
|
+
const { translate } = await resolveTranslations();
|
|
7858
|
+
const grossIssue = issues.find((issue) => issue.path === "amountGross");
|
|
7859
|
+
const netIssue = issues.find((issue) => issue.path === "amountNet");
|
|
7860
|
+
const fieldErrors: Record<string, string> = {};
|
|
7861
|
+
if (grossIssue) {
|
|
7862
|
+
fieldErrors.amountGross = translate(
|
|
7863
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross",
|
|
7864
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE,
|
|
7865
|
+
);
|
|
7866
|
+
}
|
|
7867
|
+
if (netIssue) {
|
|
7868
|
+
fieldErrors.amountNet = translate(
|
|
7869
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet",
|
|
7870
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_NET_MESSAGE,
|
|
7871
|
+
);
|
|
7872
|
+
}
|
|
7873
|
+
throw new CrudHttpError(400, {
|
|
7874
|
+
error:
|
|
7875
|
+
fieldErrors.amountGross ??
|
|
7876
|
+
fieldErrors.amountNet ??
|
|
7877
|
+
translate(
|
|
7878
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross",
|
|
7879
|
+
RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE,
|
|
7880
|
+
),
|
|
7881
|
+
fieldErrors,
|
|
7882
|
+
});
|
|
7883
|
+
}
|
|
7884
|
+
}
|
|
7769
7885
|
const calculation = await salesCalculationService.calculateDocumentTotals({
|
|
7770
7886
|
documentKind: "quote",
|
|
7771
7887
|
lines: calcLines,
|
|
@@ -523,6 +523,44 @@ export const enforceAdjustmentSign = (
|
|
|
523
523
|
*/
|
|
524
524
|
export const enforceReturnAdjustmentSign = enforceAdjustmentSign
|
|
525
525
|
|
|
526
|
+
export const RETURN_ADJUSTMENT_EXCEEDS_REMAINING_NET_MESSAGE =
|
|
527
|
+
'Return adjustment amountNet exceeds the remaining grand total. Reduce the amount or remove existing returns first.'
|
|
528
|
+
export const RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE =
|
|
529
|
+
'Return adjustment amountGross exceeds the remaining grand total. Reduce the amount or remove existing returns first.'
|
|
530
|
+
|
|
531
|
+
export type ReturnAdjustmentRemainingCheck = {
|
|
532
|
+
kind?: string | null
|
|
533
|
+
amountNet?: number | null
|
|
534
|
+
amountGross?: number | null
|
|
535
|
+
remainingNet: number
|
|
536
|
+
remainingGross: number
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export type ReturnAdjustmentRemainingIssue = {
|
|
540
|
+
path: 'amountNet' | 'amountGross'
|
|
541
|
+
message: string
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// Inclusive: abs(amount) === remaining is allowed. Tiny epsilon absorbs
|
|
545
|
+
// floating-point rounding from upstream tax/rate adjustments.
|
|
546
|
+
const RETURN_REMAINING_EPSILON = 0.005
|
|
547
|
+
|
|
548
|
+
export const validateReturnAdjustmentWithinRemaining = (
|
|
549
|
+
value: ReturnAdjustmentRemainingCheck
|
|
550
|
+
): ReturnAdjustmentRemainingIssue[] => {
|
|
551
|
+
if (value.kind !== 'return') return []
|
|
552
|
+
const absNet = typeof value.amountNet === 'number' ? Math.abs(value.amountNet) : 0
|
|
553
|
+
const absGross = typeof value.amountGross === 'number' ? Math.abs(value.amountGross) : 0
|
|
554
|
+
const issues: ReturnAdjustmentRemainingIssue[] = []
|
|
555
|
+
if (absGross > value.remainingGross + RETURN_REMAINING_EPSILON) {
|
|
556
|
+
issues.push({ path: 'amountGross', message: RETURN_ADJUSTMENT_EXCEEDS_REMAINING_GROSS_MESSAGE })
|
|
557
|
+
}
|
|
558
|
+
if (absNet > value.remainingNet + RETURN_REMAINING_EPSILON) {
|
|
559
|
+
issues.push({ path: 'amountNet', message: RETURN_ADJUSTMENT_EXCEEDS_REMAINING_NET_MESSAGE })
|
|
560
|
+
}
|
|
561
|
+
return issues
|
|
562
|
+
}
|
|
563
|
+
|
|
526
564
|
export const orderAdjustmentCreateSchema = scoped.extend({
|
|
527
565
|
orderId: uuid(),
|
|
528
566
|
orderLineId: uuid().optional(),
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
"audit_logs.resource_kind.sales.payment": "Zahlung",
|
|
5
5
|
"audit_logs.resource_kind.sales.shipment": "Versand",
|
|
6
6
|
"customers~sales.nav.group": "Vertrieb",
|
|
7
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalGross": "Der Bruttobetrag der Rücksendeanpassung überschreitet den verbleibenden Gesamtbetrag. Bitte verringern Sie den Betrag oder entfernen Sie bestehende Rücksendungen.",
|
|
8
|
+
"sales.adjustments.error.returnExceedsRemainingGrandTotalNet": "Der Nettobetrag der Rücksendeanpassung überschreitet den verbleibenden Gesamtbetrag. Bitte verringern Sie den Betrag oder entfernen Sie bestehende Rücksendungen.",
|
|
7
9
|
"sales.audit.channels.create": "Vertriebskanal erstellen",
|
|
8
10
|
"sales.audit.channels.delete": "Vertriebskanal löschen",
|
|
9
11
|
"sales.audit.channels.update": "Vertriebskanal aktualisieren",
|
|
@@ -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...",
|