fix: CSV import bugs and dashboard category filtering
Some checks failed
Release / build (windows-latest) (push) Has been cancelled
Some checks failed
Release / build (windows-latest) (push) Has been cancelled
- Fix column display for Desjardins-style quoted CSVs (apply preprocessQuotedCSV in header loading) - Fix column mapping disappearing on back-navigation (generate synthetic headers when hasHeader is false) - Fix auto-detect picking account number as amount (exclude constant-value columns, treat 0 as empty in debit/credit detection) - Use category type instead of amount sign for dashboard pie chart and recent transactions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
96ce5f3396
commit
474c7b947a
4 changed files with 18 additions and 7 deletions
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Simpl Résultat",
|
||||
"version": "0.1.1",
|
||||
"version": "0.1.2",
|
||||
"identifier": "com.simpl.resultat",
|
||||
"build": {
|
||||
"beforeDevCommand": "npm run dev",
|
||||
|
|
|
|||
|
|
@ -338,7 +338,8 @@ export function useImportWizard() {
|
|||
encoding,
|
||||
maxLines: skipLines + 5,
|
||||
});
|
||||
const parsed = Papa.parse(preview, { delimiter, skipEmptyLines: true });
|
||||
const preprocessed = preprocessQuotedCSV(preview);
|
||||
const parsed = Papa.parse(preprocessed, { delimiter, skipEmptyLines: true });
|
||||
const data = parsed.data as string[][];
|
||||
const headerRow = hasHeader && data.length > skipLines ? skipLines : -1;
|
||||
if (headerRow >= 0 && data[headerRow]) {
|
||||
|
|
@ -445,6 +446,9 @@ export function useImportWizard() {
|
|||
|
||||
if (config.hasHeader && data.length > config.skipLines) {
|
||||
headers = data[config.skipLines].map((h) => h.trim());
|
||||
} else if (!config.hasHeader && headers.length === 0 && data.length > config.skipLines) {
|
||||
const firstDataRow = data[config.skipLines];
|
||||
headers = firstDataRow.map((_, i) => `Col ${i}`);
|
||||
}
|
||||
|
||||
for (let i = startIdx; i < data.length; i++) {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export async function getExpensesByCategory(
|
|||
): Promise<CategoryBreakdownItem[]> {
|
||||
const db = await getDb();
|
||||
|
||||
const whereClauses: string[] = ["t.amount < 0"];
|
||||
const whereClauses: string[] = ["COALESCE(c.type, 'expense') = 'expense'"];
|
||||
const params: unknown[] = [];
|
||||
let paramIndex = 1;
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ export async function getRecentTransactions(
|
|||
c.name AS category_name, c.color AS category_color
|
||||
FROM transactions t
|
||||
LEFT JOIN categories c ON t.category_id = c.id
|
||||
WHERE t.amount < 0
|
||||
WHERE COALESCE(c.type, 'expense') = 'expense'
|
||||
ORDER BY t.date DESC, t.id DESC
|
||||
LIMIT $1`,
|
||||
[limit]
|
||||
|
|
|
|||
|
|
@ -220,17 +220,22 @@ function detectNumericColumns(rows: string[][], colCount: number): number[] {
|
|||
for (let col = 0; col < colCount; col++) {
|
||||
let numericCount = 0;
|
||||
let nonEmpty = 0;
|
||||
const distinctValues = new Set<number>();
|
||||
|
||||
for (const row of rows) {
|
||||
const cell = row[col]?.trim();
|
||||
if (!cell) continue;
|
||||
nonEmpty++;
|
||||
if (!isNaN(parseFrenchAmount(cell))) {
|
||||
const val = parseFrenchAmount(cell);
|
||||
if (!isNaN(val)) {
|
||||
numericCount++;
|
||||
distinctValues.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
if (nonEmpty > 0 && numericCount / nonEmpty >= 0.5) {
|
||||
// Exclude constant-value columns (e.g., account numbers, transit numbers)
|
||||
if (distinctValues.size <= 1 && nonEmpty > 2) continue;
|
||||
result.push(col);
|
||||
}
|
||||
}
|
||||
|
|
@ -444,8 +449,10 @@ function isSparseComplementary(
|
|||
for (const row of rows) {
|
||||
const cellA = row[colA]?.trim();
|
||||
const cellB = row[colB]?.trim();
|
||||
const hasA = cellA !== "" && cellA != null && !isNaN(parseFrenchAmount(cellA));
|
||||
const hasB = cellB !== "" && cellB != null && !isNaN(parseFrenchAmount(cellB));
|
||||
const valA = cellA ? parseFrenchAmount(cellA) : NaN;
|
||||
const valB = cellB ? parseFrenchAmount(cellB) : NaN;
|
||||
const hasA = !isNaN(valA) && valA !== 0;
|
||||
const hasB = !isNaN(valB) && valB !== 0;
|
||||
|
||||
if (!hasA && !hasB) continue;
|
||||
total++;
|
||||
|
|
|
|||
Loading…
Reference in a new issue