@open-mercato/core 0.6.3-develop.3588.1.2f62d1bb0d → 0.6.3-develop.3598.1.259c138c7d
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/salesUi.js +24 -1
- package/dist/helpers/integration/salesUi.js.map +2 -2
- package/dist/modules/customers/lib/personCompanyLinkTable.js +4 -36
- 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/data_sync/api/run.js +75 -65
- package/dist/modules/data_sync/api/run.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/sync_excel/api/import/route.js +126 -116
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/package.json +7 -7
- package/src/helpers/integration/salesUi.ts +26 -1
- package/src/modules/customers/lib/personCompanyLinkTable.ts +33 -50
- package/src/modules/customers/migrations/Migration20260521175027.ts +39 -0
- package/src/modules/data_sync/api/run.ts +80 -70
- package/src/modules/progress/api/jobs/route.ts +30 -20
- package/src/modules/sync_excel/api/import/route.ts +141 -131
|
@@ -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 },
|
|
189
|
+
{ status: 500 },
|
|
190
|
+
)
|
|
191
|
+
}
|
|
182
192
|
}
|