Checkpoint: Ajout du système de connecteurs web : table webImportSources, CRUD tRPC, page WebImportSources.tsx, endpoint /api/web-import/push-invoice, script cron SFR (scripts/web-import/sfr-connector.mjs)

This commit is contained in:
Manus
2026-07-30 13:53:07 +00:00
parent bcb307bde1
commit 711ce6b83a
13 changed files with 3314 additions and 2 deletions

View File

@@ -77,6 +77,12 @@ import {
deleteLearning,
deleteAllLearnings,
getBapPdfUrlsByInvoiceIds,
getWebImportSourcesByUser,
getWebImportSourceById,
createWebImportSource,
updateWebImportSource,
deleteWebImportSource,
updateWebImportSourceStatus,
} from "./db";
import { loginLocal, hashPassword, getAzureAuthUrl, isAzureAdConfigured, generateToken } from "./auth";
import { extractInvoicesWithMistral, generateMetadataJSON } from "./invoiceExtractor";
@@ -2609,5 +2615,68 @@ export const appRouter = router({
return { success: true, webUrl: result.webUrl, fileName };
}),
}),
// ============= WEB IMPORT SOURCES =============
webImportSources: router({
list: protectedProcedure.query(async ({ ctx }) => {
return getWebImportSourcesByUser(ctx.user.id);
}),
create: protectedProcedure
.input(z.object({
name: z.string().min(1).max(100),
connectorType: z.string().min(1).max(50),
portalUrl: z.string().url(),
loginEmail: z.string().min(1),
loginPassword: z.string().min(1),
frequency: z.enum(['manual', 'daily', 'weekly', 'monthly']).default('monthly'),
autoEnabled: z.number().min(0).max(1).default(0),
}))
.mutation(async ({ input, ctx }) => {
return createWebImportSource({ ...input, userId: ctx.user.id });
}),
update: protectedProcedure
.input(z.object({
id: z.number(),
name: z.string().min(1).max(100).optional(),
connectorType: z.string().min(1).max(50).optional(),
portalUrl: z.string().url().optional(),
loginEmail: z.string().min(1).optional(),
loginPassword: z.string().optional(),
frequency: z.enum(['manual', 'daily', 'weekly', 'monthly']).optional(),
autoEnabled: z.number().min(0).max(1).optional(),
}))
.mutation(async ({ input, ctx }) => {
const source = await getWebImportSourceById(input.id);
if (!source || source.userId !== ctx.user.id) {
throw new TRPCError({ code: 'NOT_FOUND', message: 'Source introuvable' });
}
const { id, ...data } = input;
await updateWebImportSource(id, data);
return { success: true };
}),
delete: protectedProcedure
.input(z.object({ id: z.number() }))
.mutation(async ({ input, ctx }) => {
const source = await getWebImportSourceById(input.id);
if (!source || source.userId !== ctx.user.id) {
throw new TRPCError({ code: 'NOT_FOUND', message: 'Source introuvable' });
}
await deleteWebImportSource(input.id);
return { success: true };
}),
getToken: protectedProcedure
.input(z.object({ id: z.number() }))
.query(async ({ input, ctx }) => {
const source = await getWebImportSourceById(input.id);
if (!source || source.userId !== ctx.user.id) {
throw new TRPCError({ code: 'NOT_FOUND', message: 'Source introuvable' });
}
return { apiToken: source.apiToken };
}),
}),
});
export type AppRouter = typeof appRouter;