Dataview: Displaying multiple tables grouped by category with subtotals

Hello,

I’m not proficient in coding, so I’ve been trying to figure it out on my own, but I’m having trouble.

What I’m trying to do

I’d like to use Dataview to visualize my budget and create a table that groups expenses by type, with a total for each type.

Things I have tried

Thanks to holroy in this topic (Dataview TABLE, GROUP BY with headers), I can create separate tables for each category:

const notes = await dv.query (`
Table without ID
Catégories, Date, file.link as Nom, Montant_depense
from "Comptabilité/Dépenses"
sort Catégories, Date
`)
console.log(notes)
if (!notes.successful) {
dv.paragraph(`~~~~\n${ notes.error }\n~~~~\n`)
return
}
let typeDict = {}
	for (let note of notes.value.values) { 
		if ( !typeDict.hasOwnProperty(note[0]) ) 
			typeDict[note[0]] = [] 
			
		typeDict[note[0]].push([...note.slice(1)])
}
for (let key of Object.keys(typeDict)) { 
	dv.header(2, key) 
	dv.table([...notes.value.headers.slice(1)], 
		typeDict[key]) 
}

Thanks to anon63144152 in this topic (Dataview Table: Summing a column), I can calculate the total of all my expenses:

const montants = await dv.query(` 
Table without ID
Catégories, Date, file.link as Nom, Montant_depense
from "Comptabilité/Dépenses"
sort Catégories, Date
WHERE number(Montant_depense) 
`)
if ( montants.successful ) { 
	const sum = montants.value.values
	 .map(a => a[3])
	 .reduce((tmp, curr) => tmp + curr, 0) 

	montants.value.values.push([, "" , "", "<span style='float: right'><strong>Total:</strong></span>", sum, " €"]) 
	dv.table(montants.value.headers, montants.value.values) 
} else
	dv.paragraph("~~~~\n" + montants.error + "\n~~~~")

However, I’d like to combine these two methods to display the total for each expense category. Could someone help me achieve this?

With the help of ChatGPT, I was able to write this code (sorry comments are in french):

// Fonction pour calculer les dates de début selon la période choisie
function getStartDateForPeriod(period) {
    let now = new Date();
    switch (period) {
        case "mois dernier":
            return new Date(now.getFullYear(), now.getMonth() - 1, 1); // Début du mois dernier
        case "3 derniers mois":
            return new Date(now.getFullYear(), now.getMonth() - 3, 1); // Début des 3 derniers mois
        case "cette année":
            return new Date(now.getFullYear(), 0, 1); // Début de cette année
        case "année dernière":
            return new Date(now.getFullYear() - 1, 0, 1); // Début de l'année dernière
        default:
            return new Date(0); // Toutes les périodes (date minimale)
    }
}

// Définis ici la période que tu veux afficher
let selectedPeriod = "3 derniers mois";  // Change cette valeur pour 'mois dernier', '3 derniers mois', 'cette année', etc.

let startDate = getStartDateForPeriod(selectedPeriod);
let endDate = selectedPeriod === "année dernière" ? new Date(startDate.getFullYear() + 1, 0, 1) : new Date(); // Fin de l'année dernière si nécessaire
let categoryTotals = {};

// Parcourt chaque fichier correspondant à la requête
for (let record of dv.pages().where(p => p.Montant_depense && p.Catégories && p.Date)) {
    let recordDate = new Date(record.Date);

    // Ne prendre en compte que les dépenses entre la date de début et de fin choisie
    if (recordDate >= startDate && recordDate < endDate) {
        let categories = Array.isArray(record.Catégories) ? record.Catégories : [record.Catégories];
        let montant = record.Montant_depense;

        // Pour chaque catégorie, ajoute le montant à la catégorie correspondante
        for (let category of categories) {
            if (!categoryTotals[category]) {
                categoryTotals[category] = 0;
            }
            categoryTotals[category] += montant;
        }
    }
}

// Affiche les catégories et les totaux sous forme de tableau
for (let category in categoryTotals) {
    dv.header(2, `Dépenses: *${category}* (<u>${selectedPeriod}</u>)`);
    
    // Filtrer les notes qui appartiennent à la catégorie actuelle et à la période choisie
    let expensesForCategory = dv.pages()
        .where(p => p.Catégories && p.Date && new Date(p.Date) >= startDate && new Date(p.Date) < endDate &&
            (Array.isArray(p.Catégories) ? p.Catégories.includes(category) : p.Catégories === category))
        .map(p => [
            p.file.link, 
            p.Date ? new Date(p.Date).toLocaleDateString('fr-FR') : "Date non définie", // Format de date en dd/MM/yyyy
            p.Montant_depense
        ]);

    // Affiche un tableau des dépenses pour cette catégorie
    dv.table(["Dépense", "Date", "Montant"], expensesForCategory);
    
    // Affiche le total des dépenses pour cette catégorie
    dv.paragraph(`Total des dépenses pour *${category}*: **${categoryTotals[category].toFixed(2)}** €`);
}

Wich give me something like this:

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.