Checkpoint: Ajout du bouton "Vérifier maintenant" pour forcer une vérification immédiate des emails sans attendre le prochain cycle automatique.
This commit is contained in:
26
.manus/db/db-query-1770806523006.json
Normal file
26
.manus/db/db-query-1770806523006.json
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"query": "SELECT * FROM importSettings;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.bd4328423008 --database fo4DRyBgjsuiigFAgNLuWm --execute SELECT * FROM importSettings;",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"id": "1",
|
||||||
|
"userId": "1",
|
||||||
|
"manualImportEnabled": "1",
|
||||||
|
"autoImportEnabled": "0",
|
||||||
|
"autoImportSourcePath": "NULL",
|
||||||
|
"autoImportFrequency": "60",
|
||||||
|
"emailImportEnabled": "1",
|
||||||
|
"emailImportAddress": "test-applicatif@itinova.org",
|
||||||
|
"emailImportPassword": "X.184037964588um",
|
||||||
|
"emailImportHost": "outlook.office365.com",
|
||||||
|
"emailImportPort": "993",
|
||||||
|
"emailImportFrequency": "2",
|
||||||
|
"createdAt": "2026-02-11 10:07:32",
|
||||||
|
"updatedAt": "2026-02-11 10:34:09"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "id\tuserId\tmanualImportEnabled\tautoImportEnabled\tautoImportSourcePath\tautoImportFrequency\temailImportEnabled\temailImportAddress\temailImportPassword\temailImportHost\temailImportPort\temailImportFrequency\tcreatedAt\tupdatedAt\n1\t1\t1\t0\tNULL\t60\t1\ttest-applicatif@itinova.org\tX.184037964588um\toutlook.office365.com\t993\t2\t2026-02-11 10:07:32\t2026-02-11 10:34:09\n",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 225
|
||||||
|
}
|
||||||
18
.manus/db/db-query-1770806548135.json
Normal file
18
.manus/db/db-query-1770806548135.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"query": "SELECT \n userId,\n emailImportEnabled,\n emailImportAddress,\n emailImportHost,\n emailImportPort,\n emailImportFrequency\nFROM importSettings;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.bd4328423008 --database fo4DRyBgjsuiigFAgNLuWm --execute SELECT \n userId,\n emailImportEnabled,\n emailImportAddress,\n emailImportHost,\n emailImportPort,\n emailImportFrequency\nFROM importSettings;",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"userId": "1",
|
||||||
|
"emailImportEnabled": "1",
|
||||||
|
"emailImportAddress": "test-applicatif@itinova.org",
|
||||||
|
"emailImportHost": "outlook.office365.com",
|
||||||
|
"emailImportPort": "993",
|
||||||
|
"emailImportFrequency": "2"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"messages": [],
|
||||||
|
"stdout": "userId\temailImportEnabled\temailImportAddress\temailImportHost\temailImportPort\temailImportFrequency\n1\t1\ttest-applicatif@itinova.org\toutlook.office365.com\t993\t2\n",
|
||||||
|
"stderr": "",
|
||||||
|
"execution_time_ms": 54
|
||||||
|
}
|
||||||
8
.manus/db/db-query-error-1770806532942.json
Normal file
8
.manus/db/db-query-error-1770806532942.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"query": "SELECT \n userId,\n manualImportEnabled,\n folderImportEnabled,\n folderImportPath,\n folderImportFrequency,\n emailImportEnabled,\n emailImportAddress,\n emailImportHost,\n emailImportPort,\n emailImportFrequency\nFROM importSettings;",
|
||||||
|
"command": "mysql --batch --raw --column-names --default-character-set=utf8mb4 --host gateway02.us-east-1.prod.aws.tidbcloud.com --port 4000 --user 4CrrYuB5tme73Qo.bd4328423008 --database fo4DRyBgjsuiigFAgNLuWm --execute SELECT \n userId,\n manualImportEnabled,\n folderImportEnabled,\n folderImportPath,\n folderImportFrequency,\n emailImportEnabled,\n emailImportAddress,\n emailImportHost,\n emailImportPort,\n emailImportFrequency\nFROM importSettings;",
|
||||||
|
"returncode": 1,
|
||||||
|
"logs": [
|
||||||
|
"ERROR 1054 (42S22) at line 1: Unknown column 'folderimportenabled' in 'field list'"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -16,6 +16,8 @@ export default function ImportSettings() {
|
|||||||
const updateMutation = trpc.importSettings.update.useMutation();
|
const updateMutation = trpc.importSettings.update.useMutation();
|
||||||
const startEmailServiceMutation = trpc.emailImportService.start.useMutation();
|
const startEmailServiceMutation = trpc.emailImportService.start.useMutation();
|
||||||
const stopEmailServiceMutation = trpc.emailImportService.stop.useMutation();
|
const stopEmailServiceMutation = trpc.emailImportService.stop.useMutation();
|
||||||
|
const checkNowEmailMutation = trpc.emailImportService.checkNow.useMutation();
|
||||||
|
const utils = trpc.useUtils();
|
||||||
const startFolderServiceMutation = trpc.folderImportService.start.useMutation();
|
const startFolderServiceMutation = trpc.folderImportService.start.useMutation();
|
||||||
const stopFolderServiceMutation = trpc.folderImportService.stop.useMutation();
|
const stopFolderServiceMutation = trpc.folderImportService.stop.useMutation();
|
||||||
|
|
||||||
@@ -413,6 +415,42 @@ export default function ImportSettings() {
|
|||||||
Service actif
|
Service actif
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{emailServiceStatus?.isRunning && (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={async () => {
|
||||||
|
try {
|
||||||
|
toast.info("V\u00e9rification en cours...", {
|
||||||
|
description: "Connexion au serveur IMAP et recherche de nouveaux emails.",
|
||||||
|
});
|
||||||
|
const result = await checkNowEmailMutation.mutateAsync();
|
||||||
|
if (result.success) {
|
||||||
|
await utils.importLogs.getByUser.invalidate();
|
||||||
|
toast.success("V\u00e9rification termin\u00e9e", {
|
||||||
|
description: result.message,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
toast.error("Erreur", {
|
||||||
|
description: result.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error: any) {
|
||||||
|
toast.error("Erreur", {
|
||||||
|
description: error.message || "Impossible de v\u00e9rifier les emails.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
disabled={checkNowEmailMutation.isPending}
|
||||||
|
>
|
||||||
|
{checkNowEmailMutation.isPending ? (
|
||||||
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
|
) : (
|
||||||
|
<Mail className="mr-2 h-4 w-4" />
|
||||||
|
)}
|
||||||
|
V\u00e9rifier maintenant
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -442,6 +442,40 @@ export function isEmailImportServiceRunning(userId: number): boolean {
|
|||||||
return activeIntervals.has(userId);
|
return activeIntervals.has(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually trigger an immediate email check for a user
|
||||||
|
*/
|
||||||
|
export async function triggerEmailCheck(userId: number): Promise<{ success: boolean; message: string }> {
|
||||||
|
try {
|
||||||
|
// Get user's import settings
|
||||||
|
const settings = await getImportSettingsByUser(userId);
|
||||||
|
|
||||||
|
if (!settings || settings.emailImportEnabled !== 1) {
|
||||||
|
return { success: false, message: "Import par email non activ\u00e9" };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!settings.emailImportAddress || !settings.emailImportPassword || !settings.emailImportHost) {
|
||||||
|
return { success: false, message: "Configuration IMAP incompl\u00e8te" };
|
||||||
|
}
|
||||||
|
|
||||||
|
const config: EmailImportConfig = {
|
||||||
|
userId,
|
||||||
|
emailAddress: settings.emailImportAddress,
|
||||||
|
password: settings.emailImportPassword,
|
||||||
|
host: settings.emailImportHost,
|
||||||
|
port: settings.emailImportPort || 993,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`[EmailImport] Manual check triggered for user ${userId}`);
|
||||||
|
await checkEmailsForPDFs(config);
|
||||||
|
|
||||||
|
return { success: true, message: "V\u00e9rification termin\u00e9e avec succ\u00e8s" };
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(`[EmailImport] Error during manual check for user ${userId}:`, error);
|
||||||
|
return { success: false, message: `Erreur: ${error.message}` };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop all email import services
|
* Stop all email import services
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { loginLocal, hashPassword, getAzureAuthUrl, isAzureAdConfigured, generat
|
|||||||
import { extractInvoicesWithMistral, generateMetadataJSON } from "./invoiceExtractor";
|
import { extractInvoicesWithMistral, generateMetadataJSON } from "./invoiceExtractor";
|
||||||
import { localStoragePut, generateStorageKey } from "./localStorage";
|
import { localStoragePut, generateStorageKey } from "./localStorage";
|
||||||
import { testSftpConnection, exportInvoiceToSftp, getUserSftpConfig } from "./sftpExport";
|
import { testSftpConnection, exportInvoiceToSftp, getUserSftpConfig } from "./sftpExport";
|
||||||
import { startEmailImportService, stopEmailImportService, isEmailImportServiceRunning } from "./emailImportService";
|
import { startEmailImportService, stopEmailImportService, isEmailImportServiceRunning, triggerEmailCheck } from "./emailImportService";
|
||||||
import { startFolderImportService, stopFolderImportService, isFolderImportServiceRunning } from "./folderImportService";
|
import { startFolderImportService, stopFolderImportService, isFolderImportServiceRunning } from "./folderImportService";
|
||||||
import { TRPCError } from "@trpc/server";
|
import { TRPCError } from "@trpc/server";
|
||||||
|
|
||||||
@@ -614,8 +614,12 @@ export const appRouter = router({
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
status: protectedProcedure.query(async ({ ctx }) => {
|
status: protectedProcedure.query(async ({ ctx }) => {
|
||||||
const isRunning = isEmailImportServiceRunning(ctx.user.id);
|
return { isRunning: isEmailImportServiceRunning(ctx.user.id) };
|
||||||
return { isRunning };
|
}),
|
||||||
|
|
||||||
|
checkNow: protectedProcedure.mutation(async ({ ctx }) => {
|
||||||
|
const result = await triggerEmailCheck(ctx.user.id);
|
||||||
|
return result;
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
8
todo.md
8
todo.md
@@ -183,3 +183,11 @@
|
|||||||
- [x] Ajouter bouton "Effacer les logs" dans la page History
|
- [x] Ajouter bouton "Effacer les logs" dans la page History
|
||||||
- [x] Ajouter confirmation avant suppression (AlertDialog)
|
- [x] Ajouter confirmation avant suppression (AlertDialog)
|
||||||
- [x] Tester la fonctionnalité
|
- [x] Tester la fonctionnalité
|
||||||
|
|
||||||
|
## Bug : Import automatique par email ne fonctionne pas
|
||||||
|
- [x] Vérifier la configuration IMAP dans la base de données
|
||||||
|
- [x] Vérifier si le service d'import email est démarré
|
||||||
|
- [x] Ajouter un bouton "Vérifier maintenant" pour forcer une vérification immédiate
|
||||||
|
- [x] Ajouter fonction triggerEmailCheck dans emailImportService
|
||||||
|
- [x] Ajouter route tRPC emailImportService.checkNow
|
||||||
|
- [ ] Tester avec un email réel et diagnostiquer les erreurs IMAP
|
||||||
|
|||||||
Reference in New Issue
Block a user