feat: import FreePro accepte .xls, .xlsx et .csv

This commit is contained in:
Manus
2026-06-05 09:20:42 -04:00
parent 6224328331
commit a4c347e554
3 changed files with 14 additions and 7 deletions

View File

@@ -226,8 +226,8 @@ function VentilationFreeProContent() {
// Gestion du fichier // Gestion du fichier
const handleFile = useCallback( const handleFile = useCallback(
(file: File) => { (file: File) => {
if (!file.name.match(/\.(xlsx|xls)$/i)) { if (!file.name.match(/\.(xlsx|xls|csv)$/i)) {
toast.error("Format invalide : veuillez sélectionner un fichier Excel (.xlsx ou .xls)"); toast.error("Format invalide : veuillez sélectionner un fichier Excel (.xlsx, .xls) ou CSV (.csv)");
return; return;
} }
const reader = new FileReader(); const reader = new FileReader();
@@ -305,7 +305,7 @@ function VentilationFreeProContent() {
<input <input
ref={fileInputRef} ref={fileInputRef}
type="file" type="file"
accept=".xlsx,.xls" accept=".xlsx,.xls,.csv"
className="hidden" className="hidden"
onChange={(e) => { const f = e.target.files?.[0]; if (f) handleFile(f); }} onChange={(e) => { const f = e.target.files?.[0]; if (f) handleFile(f); }}
/> />
@@ -320,7 +320,7 @@ function VentilationFreeProContent() {
<p className="text-sm font-medium text-foreground"> <p className="text-sm font-medium text-foreground">
Glissez-déposez le fichier Excel FreePro ici Glissez-déposez le fichier Excel FreePro ici
</p> </p>
<p className="text-xs text-muted-foreground">ou cliquez pour sélectionner (.xlsx, .xls)</p> <p className="text-xs text-muted-foreground">ou cliquez pour sélectionner (.xlsx, .xls, .csv)</p>
</div> </div>
)} )}
</div> </div>

View File

@@ -77,9 +77,16 @@ function getType(labelClient: string, script: string): string {
*/ */
export function processFreeproExcel( export function processFreeproExcel(
buffer: Buffer, buffer: Buffer,
moisLabel: string moisLabel: string,
fileName?: string
): FreeproVentilationResult { ): FreeproVentilationResult {
const wb = xlsx.read(buffer, { type: "buffer", cellDates: true }); // Détecter si c'est un CSV (par extension ou par détection du contenu)
const isCsv = fileName
? /\.csv$/i.test(fileName)
: !buffer[0] || (buffer[0] !== 0x50 && buffer[0] !== 0xD0); // PK = xlsx, D0CF = xls
const wb = isCsv
? xlsx.read(buffer.toString("utf8"), { type: "string", cellDates: true })
: xlsx.read(buffer, { type: "buffer", cellDates: true });
const ws = wb.Sheets[wb.SheetNames[0]]; const ws = wb.Sheets[wb.SheetNames[0]];
const rawRows = xlsx.utils.sheet_to_json<Record<string, unknown>>(ws, { const rawRows = xlsx.utils.sheet_to_json<Record<string, unknown>>(ws, {
header: [ header: [

View File

@@ -2218,7 +2218,7 @@ export const appRouter = router({
) )
.mutation(async ({ input, ctx }) => { .mutation(async ({ input, ctx }) => {
const buffer = Buffer.from(input.fileBase64, "base64"); const buffer = Buffer.from(input.fileBase64, "base64");
const result = processFreeproExcel(buffer, input.moisLabel); const result = processFreeproExcel(buffer, input.moisLabel, input.fileName);
const importId = await createFreeproImport( const importId = await createFreeproImport(
{ {