resanomaliedoublejustifavecqrcode

This commit is contained in:
2026-06-18 11:01:54 +02:00
parent 3178e3bf40
commit 42ab01ed41
2 changed files with 102 additions and 79 deletions
+23 -1
View File
@@ -2091,11 +2091,24 @@ app.post('/api/notes', authenticateToken, upload.any(), async (req, res) => {
} }
} }
// ── QR par ligne : téléchargement + upload en parallèle ────────── // ── QR par ligne : ne re-télécharge/ré-upload que si le client n'a pas déjà le fichier ──
await Promise.all( await Promise.all(
lignesParsed.map(async (ligne, i) => { lignesParsed.map(async (ligne, i) => {
const ligneQrRef = ligne.qrNoteRef; const ligneQrRef = ligne.qrNoteRef;
if (!ligneQrRef) return; if (!ligneQrRef) return;
// ✅ Si le client a déjà reçu ce fichier via le polling QR (origin 'qr'),
// il est déjà dans ligne.qrFiles avec son uploadUrl d'origine.
// Pas besoin de re-télécharger/ré-uploader : on évite ainsi le doublon
// causé par un nouveau nom de fichier (basé sur la référence finale de la note).
const dejaRecuParClient = Array.isArray(ligne.qrFiles) &&
ligne.qrFiles.some(f => !f.origin || f.origin === 'qr');
if (dejaRecuParClient) {
console.log(`✅ QR ligne ${i} (${ligneQrRef}) : fichier déjà reçu côté client, pas de re-upload`);
return;
}
try { try {
const qrLigne = await pool.request() const qrLigne = await pool.request()
.input('noteRef', sql.NVarChar, ligneQrRef) .input('noteRef', sql.NVarChar, ligneQrRef)
@@ -2534,9 +2547,18 @@ app.put('/api/notes/:id', authenticateToken, upload.any(), async (req, res) => {
} }
// QR par ligne // QR par ligne
// QR par ligne — skip si le client a déjà le fichier (évite doublon)
for (let i = 0; i < lignesParsed.length; i++) { for (let i = 0; i < lignesParsed.length; i++) {
const ligneQrRef = lignesParsed[i].qrNoteRef; const ligneQrRef = lignesParsed[i].qrNoteRef;
if (!ligneQrRef) continue; if (!ligneQrRef) continue;
const dejaRecuParClient = Array.isArray(lignesParsed[i].qrFiles) &&
lignesParsed[i].qrFiles.some(f => !f.origin || f.origin === 'qr');
if (dejaRecuParClient) {
console.log(`✅ [CAS1] QR ligne ${i} (${ligneQrRef}) : fichier déjà reçu côté client, pas de re-upload`);
continue;
}
try { try {
const qrLigne = await pool.request() const qrLigne = await pool.request()
.input('noteRef', sql.NVarChar, ligneQrRef) .input('noteRef', sql.NVarChar, ligneQrRef)
+2 -1
View File
@@ -1951,13 +1951,14 @@ export default function NouvelleNote({
const s = await r.json(); const s = await r.json();
if (s.uploaded) { if (s.uploaded) {
clearInterval(qrPollingRefs.current[depenseId]); clearInterval(qrPollingRefs.current[depenseId]);
delete qrPollingRefs.current[depenseId]; // ✅ empêche un 2e tick concurrent de re-déclencher la fusion
setDepenses(prev => prev.map(d => d.id === depenseId setDepenses(prev => prev.map(d => d.id === depenseId
? { ? {
...d, qrUploaded: true, qrLink: null, ...d, qrUploaded: true, qrLink: null,
qrFiles: [ qrFiles: [
...(d.qrFiles ?? []), ...(d.qrFiles ?? []),
...(Array.isArray(s.files) ? s.files.map((f: any) => ({ ...f, origin: 'qr' as const })) : []) ...(Array.isArray(s.files) ? s.files.map((f: any) => ({ ...f, origin: 'qr' as const })) : [])
] ].filter((f, i, arr) => arr.findIndex(x => x.uploadUrl === f.uploadUrl) === i) // ✅ dédup par URL
} }
: d)); : d));
} }