create-mercato-app 0.5.1-develop.2691.d8a0934b37 → 0.5.1-develop.2694.732417c5ec
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/package.json +1 -1
- package/template/src/app/page.tsx +5 -3
- package/template/src/modules/example/api/todos/route.ts +26 -19
- package/template/src/modules/example/commands/todos.ts +1 -1
- package/template/src/modules/example/data/entities.ts +1 -1
- package/template/src/modules/example_customers_sync/api/example-customers-sync/mappings/route.ts +18 -13
- package/template/src/modules/example_customers_sync/data/entities.ts +1 -1
- package/template/src/modules/example_customers_sync/lib/mappings.ts +1 -1
- package/template/src/modules/example_customers_sync/lib/sync.ts +17 -14
package/package.json
CHANGED
|
@@ -11,6 +11,8 @@ import Link from 'next/link'
|
|
|
11
11
|
import { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'
|
|
12
12
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
13
13
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
14
|
+
import { User } from '@open-mercato/core/modules/auth/data/entities'
|
|
15
|
+
import { Tenant, Organization } from '@open-mercato/core/modules/directory/data/entities'
|
|
14
16
|
|
|
15
17
|
function FeatureBadge({ label }: { label: string }) {
|
|
16
18
|
return (
|
|
@@ -60,9 +62,9 @@ export default async function Home() {
|
|
|
60
62
|
try {
|
|
61
63
|
const container = await createRequestContainer()
|
|
62
64
|
const em = container.resolve<EntityManager>('em')
|
|
63
|
-
usersCount = await em.count(
|
|
64
|
-
tenantsCount = await em.count(
|
|
65
|
-
orgsCount = await em.count(
|
|
65
|
+
usersCount = await em.count(User, {})
|
|
66
|
+
tenantsCount = await em.count(Tenant, {})
|
|
67
|
+
orgsCount = await em.count(Organization, {})
|
|
66
68
|
dbStatus = t('app.page.dbStatus.connected', 'Connected')
|
|
67
69
|
} catch (error: unknown) {
|
|
68
70
|
const message = error instanceof Error ? error.message : t('app.page.dbStatus.noConnection', 'no connection')
|
|
@@ -191,25 +191,32 @@ export const { metadata, GET, POST, PUT, DELETE } = makeCrudRoute({
|
|
|
191
191
|
.map((d: any) => d.key)
|
|
192
192
|
// Fallback discovery: keys that have values even if no definition exists
|
|
193
193
|
try {
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
.
|
|
197
|
-
.
|
|
198
|
-
.
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
.
|
|
194
|
+
const db = (em as any).getKysely()
|
|
195
|
+
let cfvQuery = db
|
|
196
|
+
.selectFrom('custom_field_values')
|
|
197
|
+
.select('field_key')
|
|
198
|
+
.distinct()
|
|
199
|
+
.where('entity_id', '=', ENTITY_ID as any)
|
|
200
|
+
.where('deleted_at', 'is', null)
|
|
201
|
+
if (scopedOrgIds === null) {
|
|
202
|
+
// no organization restriction
|
|
203
|
+
} else if (scopedOrgIds.length > 0) {
|
|
204
|
+
cfvQuery = cfvQuery.where((eb: any) => eb.or([
|
|
205
|
+
eb('organization_id', 'in', scopedOrgIds),
|
|
206
|
+
eb('organization_id', 'is', null),
|
|
207
|
+
]))
|
|
208
|
+
} else {
|
|
209
|
+
cfvQuery = cfvQuery.where('organization_id', 'is', null)
|
|
210
|
+
}
|
|
211
|
+
if (ctx.auth!.tenantId != null) {
|
|
212
|
+
cfvQuery = cfvQuery.where((eb: any) => eb.or([
|
|
213
|
+
eb('tenant_id', '=', ctx.auth!.tenantId),
|
|
214
|
+
eb('tenant_id', 'is', null),
|
|
215
|
+
]))
|
|
216
|
+
} else {
|
|
217
|
+
cfvQuery = cfvQuery.where('tenant_id', 'is', null)
|
|
218
|
+
}
|
|
219
|
+
const rows = await cfvQuery.execute()
|
|
213
220
|
const keysFromValues = (rows || []).map((r: any) => String(r.field_key))
|
|
214
221
|
// Merge with code-declared keys and de-dupe
|
|
215
222
|
dynamicCfKeys = Array.from(new Set([ ...cfSel.keys, ...keysFromDefs, ...keysFromValues ]))
|
|
@@ -407,7 +407,7 @@ const deleteTodoCommand: CommandHandler<{ body?: Record<string, unknown>; query?
|
|
|
407
407
|
restored.isDone = before.is_done
|
|
408
408
|
restored.tenantId = before.tenantId ?? scope.tenantId
|
|
409
409
|
restored.organizationId = before.organizationId ?? scope.organizationId
|
|
410
|
-
await em.
|
|
410
|
+
await em.persist(restored).flush()
|
|
411
411
|
} else {
|
|
412
412
|
restored = await de.createOrmEntity({
|
|
413
413
|
entity: Todo,
|
package/template/src/modules/example_customers_sync/api/example-customers-sync/mappings/route.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { NextResponse } from 'next/server'
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
4
|
+
import { type Kysely } from 'kysely'
|
|
4
5
|
import { getAuthFromRequest } from '@open-mercato/shared/lib/auth/server'
|
|
5
6
|
import { createRequestContainer } from '@open-mercato/shared/lib/di/container'
|
|
6
7
|
import { findWithDecryption } from '@open-mercato/shared/lib/encryption/find'
|
|
@@ -82,9 +83,10 @@ export async function GET(request: Request) {
|
|
|
82
83
|
: []
|
|
83
84
|
|
|
84
85
|
const em = (container.resolve('em') as EntityManager).fork()
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
.
|
|
86
|
+
const db = (em as any).getKysely() as Kysely<any>
|
|
87
|
+
let rowsQuery = db
|
|
88
|
+
.selectFrom('example_customer_interaction_mappings')
|
|
89
|
+
.select([
|
|
88
90
|
'id',
|
|
89
91
|
'interaction_id',
|
|
90
92
|
'todo_id',
|
|
@@ -97,29 +99,32 @@ export async function GET(request: Request) {
|
|
|
97
99
|
'organization_id',
|
|
98
100
|
'tenant_id',
|
|
99
101
|
])
|
|
100
|
-
.where('tenant_id', auth.tenantId)
|
|
102
|
+
.where('tenant_id', '=', auth.tenantId)
|
|
101
103
|
.orderBy('updated_at', 'desc')
|
|
102
104
|
.orderBy('id', 'desc')
|
|
103
105
|
.limit(query.limit + 1)
|
|
104
106
|
|
|
105
107
|
if (organizationIds.length > 0) {
|
|
106
|
-
rowsQuery.
|
|
108
|
+
rowsQuery = rowsQuery.where('organization_id', 'in', organizationIds)
|
|
107
109
|
}
|
|
108
110
|
if (query.interactionId) {
|
|
109
|
-
rowsQuery.
|
|
111
|
+
rowsQuery = rowsQuery.where('interaction_id', '=', query.interactionId)
|
|
110
112
|
}
|
|
111
113
|
if (query.todoId) {
|
|
112
|
-
rowsQuery.
|
|
114
|
+
rowsQuery = rowsQuery.where('todo_id', '=', query.todoId)
|
|
113
115
|
}
|
|
114
116
|
if (cursor) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
const cursorDate = new Date(cursor.updatedAt)
|
|
118
|
+
rowsQuery = rowsQuery.where(eb => eb.or([
|
|
119
|
+
eb('updated_at', '<', cursorDate),
|
|
120
|
+
eb.and([
|
|
121
|
+
eb('updated_at', '=', cursorDate),
|
|
122
|
+
eb('id', '<', cursor.id),
|
|
123
|
+
]),
|
|
124
|
+
]))
|
|
120
125
|
}
|
|
121
126
|
|
|
122
|
-
const rows = await rowsQuery
|
|
127
|
+
const rows = (await rowsQuery.execute()) as MappingRow[]
|
|
123
128
|
const pageRows = rows.slice(0, query.limit)
|
|
124
129
|
const interactionIds = Array.from(new Set(pageRows.map((row) => row.interaction_id)))
|
|
125
130
|
const interactions = interactionIds.length > 0
|
|
@@ -247,6 +247,6 @@ export async function deleteExampleCustomerInteractionMapping(
|
|
|
247
247
|
mapping: ExampleCustomerInteractionMapping | null | undefined,
|
|
248
248
|
): Promise<boolean> {
|
|
249
249
|
if (!mapping) return false
|
|
250
|
-
await em.
|
|
250
|
+
await em.remove(mapping).flush()
|
|
251
251
|
return true
|
|
252
252
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EntityManager } from '@mikro-orm/postgresql'
|
|
2
|
+
import { type Kysely } from 'kysely'
|
|
2
3
|
import type { CommandBus } from '@open-mercato/shared/lib/commands'
|
|
3
4
|
import { loadCustomFieldSnapshot } from '@open-mercato/shared/lib/commands/customFieldSnapshots'
|
|
4
5
|
import { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'
|
|
@@ -720,34 +721,36 @@ async function loadLegacyExampleTodoLinks(
|
|
|
720
721
|
cursor?: string,
|
|
721
722
|
): Promise<{ rows: LegacyExampleTodoLinkRow[]; nextCursor?: string }> {
|
|
722
723
|
const em = (container.resolve('em') as EntityManager).fork()
|
|
723
|
-
const
|
|
724
|
+
const db = (em as any).getKysely() as Kysely<any>
|
|
724
725
|
const parsedCursor = decodeCursor(cursor)
|
|
725
|
-
|
|
726
|
-
.
|
|
726
|
+
let query = db
|
|
727
|
+
.selectFrom('customer_todo_links')
|
|
728
|
+
.select([
|
|
727
729
|
'id',
|
|
728
730
|
'entity_id as entityId',
|
|
729
731
|
'todo_id as todoId',
|
|
730
732
|
'created_by_user_id as createdByUserId',
|
|
731
733
|
'created_at as createdAt',
|
|
732
734
|
])
|
|
733
|
-
.where(
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
todo_source: 'example:todo',
|
|
737
|
-
})
|
|
735
|
+
.where('tenant_id', '=', scope.tenantId)
|
|
736
|
+
.where('organization_id', '=', scope.organizationId)
|
|
737
|
+
.where('todo_source', '=', 'example:todo')
|
|
738
738
|
.orderBy('created_at', 'asc')
|
|
739
739
|
.orderBy('id', 'asc')
|
|
740
740
|
.limit(limit + 1)
|
|
741
741
|
|
|
742
742
|
if (parsedCursor) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
743
|
+
const cursorDate = new Date(parsedCursor.createdAt)
|
|
744
|
+
query = query.where(eb => eb.or([
|
|
745
|
+
eb('created_at', '>', cursorDate),
|
|
746
|
+
eb.and([
|
|
747
|
+
eb('created_at', '=', cursorDate),
|
|
748
|
+
eb('id', '>', parsedCursor.id),
|
|
749
|
+
]),
|
|
750
|
+
]))
|
|
748
751
|
}
|
|
749
752
|
|
|
750
|
-
const rows = await query
|
|
753
|
+
const rows = (await query.execute()) as LegacyExampleTodoLinkRow[]
|
|
751
754
|
const pageRows = rows.slice(0, limit)
|
|
752
755
|
const next = rows.length > limit ? pageRows[pageRows.length - 1] : null
|
|
753
756
|
return {
|