Ctrl K
ComunidadGuías…

server/controllers/budgets.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import type express from 'express';
import { asString, asyncErr, KError } from '../helpers';
import { Budget, Category } from '../models';
import { checkBudget } from '../shared/validators';
import type { IdentifiedRequest, PreloadedRequest } from './routes';

async function createBudget(
    userId: number,
    budget: {
        viewId: number;
        year: number;
        month: number;
        categoryId: number;
        threshold: number | null;
    }
) {
    // Missing parameters
    if (typeof budget.categoryId !== 'undefined') {
        const categoryExists = await Category.exists(userId, budget.categoryId);
        if (!categoryExists) {
            throw new KError(`Category ${budget.categoryId} not found`, 404);
        }
    }

    const error = checkBudget(budget);
    if (error) {
        throw new KError(error, 400);
    }

    return await Budget.create(userId, budget);
}

export async function getByYearAndMonth(req: IdentifiedRequest<Budget>, res: express.Response) {
    try {
        const { id: userId } = req.user;
        const { viewId: viewIdStr, year: yearStr, month: monthStr } = req.params;

        const viewId = Number.parseInt(asString(viewIdStr), 10);
        if (Number.isNaN(viewId)) {
            throw new KError('Invalid viewId parameter', 400);
        }

        const year = Number.parseInt(asString(yearStr), 10);
        if (Number.isNaN(year)) {
            throw new KError('Invalid year parameter', 400);
        }

        const month = Number.parseInt(asString(monthStr), 10);
        if (Number.isNaN(month) || month < 0 || month > 11) {
            throw new KError('Invalid month parameter', 400);
        }

        const budgets = await Budget.byYearAndMonth(userId, viewId, year, month);

        // Ensure there is a budget for each category.
        const categories = await Category.all(userId);
        for (const cat of categories) {
            if (!budgets.find(b => b.categoryId === cat.id)) {
                // Retrieve the last threshold used for this category instead of defaulting to 0.
                // "last" here means "last in time" not last entered (TODO: fix it when we'll be
                // able to sort by creation/update order).
                const sameCategoryBudgets = await Budget.byCategory(userId, viewId, cat.id);
                let currentYear = 0;
                let currentMonth = 0;
                let threshold: number | null = null;

                for (const b of sameCategoryBudgets) {
                    if (
                        b.year > currentYear ||
                        (b.year === currentYear && b.month > currentMonth)
                    ) {
                        currentYear = b.year;
                        currentMonth = b.month;
                        threshold = b.threshold;
                    }
                }

                const budget = await createBudget(userId, {
                    viewId,
                    year,
                    month,
                    categoryId: cat.id,
                    threshold,
                });

                budgets.push(budget);
            }
        }

        res.status(200).json({
            viewId,
            year,
            month,
            budgets,
        });
    } catch (err) {
        asyncErr(res, err, 'when loading budgets by year/month');
    }
}

export async function update(req: PreloadedRequest<Budget>, res: express.Response) {
    try {
        const { id: userId } = req.user;

        const params = req.body;
        const { viewId: viewIdStr, year: yearStr, month: monthStr, budgetCatId } = req.params;

        const viewId = Number.parseInt(asString(viewIdStr), 10);
        const year = Number.parseInt(asString(yearStr), 10);
        const month = Number.parseInt(asString(monthStr), 10);
        const categoryId = Number.parseInt(asString(budgetCatId), 10);

        const error = checkBudget({
            viewId,
            year,
            month,
            threshold: params.threshold,
        });
        if (error) {
            throw new KError(error, 400);
        }

        const newBudget = await Budget.findAndUpdate(
            userId,
            viewId,
            categoryId,
            year,
            month,
            params.threshold
        );
        res.status(200).json(newBudget);
    } catch (err) {
        asyncErr(res, err, 'when updating a budget');
    }
}