@open-mercato/core 0.6.6-develop.6404.1.e2f8d5025a → 0.6.6-develop.6407.1.9a4c26cf6a
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/modules/attachments/api/route.js +10 -4
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/catalog/api/settings/route.js +142 -0
- package/dist/modules/catalog/api/settings/route.js.map +7 -0
- package/dist/modules/catalog/backend/config/catalog/page.js +6 -2
- package/dist/modules/catalog/backend/config/catalog/page.js.map +2 -2
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js +89 -0
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js.map +7 -0
- package/dist/modules/catalog/components/products/ProductUomSection.js +4 -2
- package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
- package/dist/modules/catalog/components/products/hooks/useUnitPriceDisplayEnabled.js +25 -0
- package/dist/modules/catalog/components/products/hooks/useUnitPriceDisplayEnabled.js.map +7 -0
- package/dist/modules/catalog/lib/settings.js +9 -0
- package/dist/modules/catalog/lib/settings.js.map +7 -0
- package/dist/modules/customers/api/pipeline-stages/route.js +6 -4
- package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
- package/dist/modules/customers/api/pipelines/route.js +5 -3
- package/dist/modules/customers/api/pipelines/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/assignable/route.js +7 -11
- package/dist/modules/staff/api/team-members/assignable/route.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/attachments/api/route.ts +20 -4
- package/src/modules/attachments/i18n/de.json +1 -0
- package/src/modules/attachments/i18n/en.json +1 -0
- package/src/modules/attachments/i18n/es.json +1 -0
- package/src/modules/attachments/i18n/pl.json +1 -0
- package/src/modules/catalog/api/settings/route.ts +165 -0
- package/src/modules/catalog/backend/config/catalog/page.tsx +2 -0
- package/src/modules/catalog/components/UnitPriceDisplaySettings.tsx +106 -0
- package/src/modules/catalog/components/products/ProductUomSection.tsx +4 -0
- package/src/modules/catalog/components/products/hooks/useUnitPriceDisplayEnabled.ts +39 -0
- package/src/modules/catalog/i18n/de.json +8 -0
- package/src/modules/catalog/i18n/en.json +8 -0
- package/src/modules/catalog/i18n/es.json +8 -0
- package/src/modules/catalog/i18n/pl.json +8 -0
- package/src/modules/catalog/lib/settings.ts +8 -0
- package/src/modules/customers/api/pipeline-stages/route.ts +6 -4
- package/src/modules/customers/api/pipelines/route.ts +5 -3
- package/src/modules/staff/api/team-members/assignable/route.ts +8 -12
|
@@ -614,6 +614,14 @@
|
|
|
614
614
|
"catalog.search.priceKind.promotion": "Promoción",
|
|
615
615
|
"catalog.search.status.inactive": "Inactivo",
|
|
616
616
|
"catalog.search.variant.default": "Predeterminado",
|
|
617
|
+
"catalog.settings.loading": "Cargando…",
|
|
618
|
+
"catalog.settings.messages.saved": "Ajustes guardados.",
|
|
619
|
+
"catalog.settings.unitPriceDisplay.description": "Controla si la función de presentación del precio unitario de la UE está disponible en el formulario de producto.",
|
|
620
|
+
"catalog.settings.unitPriceDisplay.errors.load": "No se pudieron cargar los ajustes del catálogo.",
|
|
621
|
+
"catalog.settings.unitPriceDisplay.errors.save": "No se pudieron guardar los ajustes del catálogo.",
|
|
622
|
+
"catalog.settings.unitPriceDisplay.title": "Presentación del precio unitario",
|
|
623
|
+
"catalog.settings.unitPriceDisplay.toggleDescription": "Cuando está desactivado, los ajustes del precio unitario de la UE se ocultan en todos los formularios de producto. Desactívalo para fabricantes u otros inquilinos que no venden a consumidores.",
|
|
624
|
+
"catalog.settings.unitPriceDisplay.toggleLabel": "Activar la presentación del precio unitario de la UE",
|
|
617
625
|
"catalog.stats.active": "Activos",
|
|
618
626
|
"catalog.stats.categories": "Categorías",
|
|
619
627
|
"catalog.stats.products": "Productos",
|
|
@@ -614,6 +614,14 @@
|
|
|
614
614
|
"catalog.search.priceKind.promotion": "Promocja",
|
|
615
615
|
"catalog.search.status.inactive": "Nieaktywny",
|
|
616
616
|
"catalog.search.variant.default": "Domyślny",
|
|
617
|
+
"catalog.settings.loading": "Ładowanie…",
|
|
618
|
+
"catalog.settings.messages.saved": "Ustawienia zapisane.",
|
|
619
|
+
"catalog.settings.unitPriceDisplay.description": "Określa, czy funkcja prezentacji ceny jednostkowej UE jest dostępna w formularzu produktu.",
|
|
620
|
+
"catalog.settings.unitPriceDisplay.errors.load": "Nie udało się wczytać ustawień katalogu.",
|
|
621
|
+
"catalog.settings.unitPriceDisplay.errors.save": "Nie udało się zapisać ustawień katalogu.",
|
|
622
|
+
"catalog.settings.unitPriceDisplay.title": "Prezentacja ceny jednostkowej",
|
|
623
|
+
"catalog.settings.unitPriceDisplay.toggleDescription": "Gdy wyłączone, ustawienia ceny jednostkowej UE są ukryte w każdym formularzu produktu. Wyłącz tę opcję dla firm produkcyjnych lub innych najemców, którzy nie sprzedają konsumentom.",
|
|
624
|
+
"catalog.settings.unitPriceDisplay.toggleLabel": "Włącz prezentację ceny jednostkowej UE",
|
|
617
625
|
"catalog.stats.active": "Aktywne",
|
|
618
626
|
"catalog.stats.categories": "Kategorie",
|
|
619
627
|
"catalog.stats.products": "Produkty",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const CATALOG_SETTINGS_MODULE_ID = 'catalog'
|
|
2
|
+
|
|
3
|
+
// Controls whether the EU unit-price presentation feature is exposed at all.
|
|
4
|
+
// Default ON so existing tenants keep the current behavior; manufacturers or
|
|
5
|
+
// other non-retail tenants can turn it off to remove the settings from the
|
|
6
|
+
// product form entirely.
|
|
7
|
+
export const UNIT_PRICE_DISPLAY_ENABLED_KEY = 'unit_price_display_enabled'
|
|
8
|
+
export const UNIT_PRICE_DISPLAY_ENABLED_DEFAULT = true
|
|
@@ -3,6 +3,7 @@ import { z } from 'zod'
|
|
|
3
3
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
4
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
|
|
6
|
+
import { resolveOrganizationScopeFilter } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'
|
|
6
7
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
7
8
|
import type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'
|
|
8
9
|
import { CustomerPipelineStage, CustomerDictionaryEntry } from '../../data/entities'
|
|
@@ -56,15 +57,16 @@ async function buildContext(
|
|
|
56
57
|
|
|
57
58
|
export async function GET(req: Request) {
|
|
58
59
|
try {
|
|
59
|
-
const { ctx,
|
|
60
|
-
if (!
|
|
60
|
+
const { ctx, tenantId, translate } = await buildContext(req)
|
|
61
|
+
if (!tenantId) {
|
|
61
62
|
return NextResponse.json({ error: translate('customers.errors.context_required', 'Organization and tenant context required') }, { status: 400 })
|
|
62
63
|
}
|
|
64
|
+
const orgFilter = resolveOrganizationScopeFilter(ctx.organizationScope, ctx.auth)
|
|
63
65
|
const url = new URL(req.url)
|
|
64
66
|
const pipelineId = url.searchParams.get('pipelineId')
|
|
65
67
|
|
|
66
68
|
const em = (ctx.container.resolve('em') as EntityManager)
|
|
67
|
-
const where: Record<string, unknown> = {
|
|
69
|
+
const where: Record<string, unknown> = { tenantId, ...orgFilter.where }
|
|
68
70
|
if (pipelineId) where.pipelineId = pipelineId
|
|
69
71
|
|
|
70
72
|
const stages = await em.find(CustomerPipelineStage, where, { orderBy: { order: 'ASC' } })
|
|
@@ -72,8 +74,8 @@ export async function GET(req: Request) {
|
|
|
72
74
|
const stageLabels = stages.map((s) => s.label.trim().toLowerCase())
|
|
73
75
|
const dictEntries = stageLabels.length
|
|
74
76
|
? await em.find(CustomerDictionaryEntry, {
|
|
75
|
-
organizationId,
|
|
76
77
|
tenantId,
|
|
78
|
+
...orgFilter.where,
|
|
77
79
|
kind: 'pipeline_stage',
|
|
78
80
|
normalizedValue: { $in: stageLabels },
|
|
79
81
|
})
|
|
@@ -3,6 +3,7 @@ import { z } from 'zod'
|
|
|
3
3
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
4
4
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
5
|
import { resolveOrganizationScopeForRequest } from '@open-mercato/core/modules/directory/utils/organizationScope'
|
|
6
|
+
import { resolveOrganizationScopeFilter } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'
|
|
6
7
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
7
8
|
import type { CommandRuntimeContext, CommandBus } from '@open-mercato/shared/lib/commands'
|
|
8
9
|
import { CustomerPipeline } from '../../data/entities'
|
|
@@ -56,15 +57,16 @@ async function buildContext(
|
|
|
56
57
|
|
|
57
58
|
export async function GET(req: Request) {
|
|
58
59
|
try {
|
|
59
|
-
const { ctx,
|
|
60
|
-
if (!
|
|
60
|
+
const { ctx, tenantId, translate } = await buildContext(req)
|
|
61
|
+
if (!tenantId) {
|
|
61
62
|
return NextResponse.json({ error: translate('customers.errors.context_required', 'Organization and tenant context required') }, { status: 400 })
|
|
62
63
|
}
|
|
64
|
+
const orgFilter = resolveOrganizationScopeFilter(ctx.organizationScope, ctx.auth)
|
|
63
65
|
const url = new URL(req.url)
|
|
64
66
|
const isDefaultParam = url.searchParams.get('isDefault')
|
|
65
67
|
|
|
66
68
|
const em = (ctx.container.resolve('em') as EntityManager)
|
|
67
|
-
const where: Record<string, unknown> = {
|
|
69
|
+
const where: Record<string, unknown> = { tenantId, ...orgFilter.where }
|
|
68
70
|
if (isDefaultParam === 'true') where.isDefault = true
|
|
69
71
|
if (isDefaultParam === 'false') where.isDefault = false
|
|
70
72
|
|
|
@@ -6,6 +6,7 @@ import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
|
6
6
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
7
7
|
import { createPagedListResponseSchema as createSharedPagedListResponseSchema } from '@open-mercato/shared/lib/openapi/crud'
|
|
8
8
|
import type { RbacService } from '@open-mercato/core/modules/auth/services/rbacService'
|
|
9
|
+
import { resolveOrganizationScopeFilter } from '@open-mercato/core/modules/directory/utils/organizationScopeFilter'
|
|
9
10
|
import { User } from '@open-mercato/core/modules/auth/data/entities'
|
|
10
11
|
import {
|
|
11
12
|
resolveAuthActorId,
|
|
@@ -57,7 +58,7 @@ export const metadata = {
|
|
|
57
58
|
async function canAccessAssignableStaff(
|
|
58
59
|
rbac: RbacService | undefined,
|
|
59
60
|
userId: string,
|
|
60
|
-
scope: { tenantId: string; organizationId: string },
|
|
61
|
+
scope: { tenantId: string; organizationId: string | null },
|
|
61
62
|
): Promise<boolean> {
|
|
62
63
|
if (!rbac) return false
|
|
63
64
|
if (
|
|
@@ -72,18 +73,13 @@ export async function GET(request: Request) {
|
|
|
72
73
|
const { translate } = await resolveTranslations()
|
|
73
74
|
try {
|
|
74
75
|
const query = querySchema.parse(Object.fromEntries(new URL(request.url).searchParams))
|
|
75
|
-
const { container, em, auth,
|
|
76
|
+
const { container, em, auth, scope: organizationScope } = await resolveCustomersRequestContext(request)
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
throw new CrudHttpError(
|
|
79
|
-
400,
|
|
80
|
-
{ error: translate('customers.errors.organization_required', 'Organization context is required') },
|
|
81
|
-
)
|
|
82
|
-
}
|
|
78
|
+
const orgFilter = resolveOrganizationScopeFilter(organizationScope, auth)
|
|
83
79
|
|
|
84
80
|
const actorId = resolveAuthActorId(auth)
|
|
85
81
|
const rbacService = container.resolve('rbacService') as RbacService | undefined
|
|
86
|
-
const scope = { tenantId: auth.tenantId, organizationId:
|
|
82
|
+
const scope = { tenantId: auth.tenantId, organizationId: orgFilter.rbacOrganizationId }
|
|
87
83
|
const hasAccess = await canAccessAssignableStaff(rbacService, actorId, scope)
|
|
88
84
|
if (!hasAccess) {
|
|
89
85
|
throw new CrudHttpError(
|
|
@@ -104,7 +100,7 @@ export async function GET(request: Request) {
|
|
|
104
100
|
StaffTeamMember,
|
|
105
101
|
{
|
|
106
102
|
tenantId: auth.tenantId,
|
|
107
|
-
|
|
103
|
+
...orgFilter.where,
|
|
108
104
|
deletedAt: null,
|
|
109
105
|
isActive: true,
|
|
110
106
|
},
|
|
@@ -136,7 +132,7 @@ export async function GET(request: Request) {
|
|
|
136
132
|
id: { $in: userIds },
|
|
137
133
|
deletedAt: null,
|
|
138
134
|
tenantId: auth.tenantId,
|
|
139
|
-
|
|
135
|
+
...orgFilter.where,
|
|
140
136
|
},
|
|
141
137
|
undefined,
|
|
142
138
|
scope,
|
|
@@ -150,7 +146,7 @@ export async function GET(request: Request) {
|
|
|
150
146
|
id: { $in: teamIds },
|
|
151
147
|
deletedAt: null,
|
|
152
148
|
tenantId: auth.tenantId,
|
|
153
|
-
|
|
149
|
+
...orgFilter.where,
|
|
154
150
|
},
|
|
155
151
|
undefined,
|
|
156
152
|
scope,
|