Files
PantryHub/controllers/ProductController.js

219 lines
6.9 KiB
JavaScript

const ProductService =
require("../services/ProductService");
const CategoryService = require("../services/CategoryService");
const FavoriteService = require("../services/FavoriteService");
const parseCsv = require("../utils/parseCsv");
class ProductController {
index(req, res) {
const products = ProductService.getProducts(req.user.household_id);
const favoriteIds = FavoriteService.getFavoriteIds(req.user.id, req.user.household_id);
const categories = CategoryService.getCategories(req.user.household_id);
res.render(
"products/index",
{
title:"Producten",
products: products.map(product => ({
...product,
is_favorite: favoriteIds.has(product.id)
})),
categories
}
);
}
create(req, res) {
const name = (req.body.name || "").trim();
const categoryId = req.body.category_id
? Number.parseInt(req.body.category_id, 10)
: null;
if (!name || (categoryId !== null && !Number.isInteger(categoryId))) {
req.flash("error", "Geef een geldige productnaam en categorie op.");
return res.redirect("/products");
}
if (categoryId !== null && !CategoryService.getCategory(categoryId, req.user.household_id)) {
req.flash("error", "De gekozen categorie bestaat niet.");
return res.redirect("/products");
}
ProductService.createProduct({
name,
category_id: categoryId,
household_id: req.user.household_id
});
req.flash("success", "Product toegevoegd.");
res.redirect("/products");
}
import(req, res) {
if (!req.file) {
req.flash("error", "Kies eerst een CSV-bestand.");
return res.redirect("/products");
}
let rows;
try {
rows = parseCsv(req.file.buffer.toString("utf8").replace(/^\uFEFF/, ""));
} catch (error) {
req.flash("error", `CSV kan niet worden gelezen: ${error.message}`);
return res.redirect("/products");
}
if (rows.length < 2) {
req.flash("error", "Het CSV-bestand bevat geen producten.");
return res.redirect("/products");
}
const headers = rows[0].map(header => header.trim().toLowerCase());
const nameIndex = headers.indexOf("name");
const categoryIndex = headers.includes("category")
? headers.indexOf("category")
: headers.indexOf("category_name");
const barcodeIndex = headers.indexOf("barcode");
if (nameIndex === -1) {
req.flash("error", "De CSV moet een kolom 'name' bevatten.");
return res.redirect("/products");
}
const categories = CategoryService.getCategories(req.user.household_id);
const categoryIds = new Map(
categories.map(category => [category.name.trim().toLowerCase(), category.id])
);
const products = [];
const errors = [];
rows.slice(1).forEach((row, rowIndex) => {
const lineNumber = rowIndex + 2;
const name = (row[nameIndex] || "").trim();
const categoryName = categoryIndex === -1
? ""
: (row[categoryIndex] || "").trim();
const categoryId = categoryName
? categoryIds.get(categoryName.toLowerCase())
: null;
if (!name) errors.push(`regel ${lineNumber}: productnaam ontbreekt`);
if (categoryName && !categoryId) {
errors.push(`regel ${lineNumber}: categorie '${categoryName}' bestaat niet`);
}
products.push({
name,
category_id: categoryId,
barcode: barcodeIndex === -1 ? "" : (row[barcodeIndex] || "").trim(),
household_id: req.user.household_id
});
});
if (errors.length > 0) {
req.flash("error", `Import afgebroken: ${errors.slice(0, 5).join("; ")}`);
return res.redirect("/products");
}
ProductService.createProducts(products);
req.flash("success", `${products.length} producten geïmporteerd.`);
res.redirect("/products");
}
editForm(req, res) {
const productId = Number.parseInt(req.params.id, 10);
const product = Number.isInteger(productId)
? ProductService.getProduct(productId, req.user.household_id)
: null;
if (!product) {
req.flash("error", "Product niet gevonden.");
return res.redirect("/products");
}
const categories = CategoryService.getCategories(req.user.household_id);
res.render("products/edit", {
title: "Product wijzigen",
product,
categories
});
}
update(req, res) {
const productId = Number.parseInt(req.params.id, 10);
const name = (req.body.name || "").trim();
const categoryId = req.body.category_id
? Number.parseInt(req.body.category_id, 10)
: null;
if (!Number.isInteger(productId) || !name ||
(categoryId !== null && !Number.isInteger(categoryId))) {
req.flash("error", "Geef een geldige productnaam en categorie op.");
return res.redirect("/products");
}
if (categoryId !== null && !CategoryService.getCategory(categoryId, req.user.household_id)) {
req.flash("error", "De gekozen categorie bestaat niet.");
return res.redirect(`/products/${productId}/edit`);
}
const result = ProductService.updateProduct(productId, req.user.household_id, {
name,
category_id: categoryId
});
if (result.changes === 0) {
req.flash("error", "Product niet gevonden.");
return res.redirect("/products");
}
req.flash("success", "Product gewijzigd.");
res.redirect("/products");
}
remove(req, res) {
const productId = Number.parseInt(req.params.id, 10);
if (!Number.isInteger(productId)) {
req.flash("error", "Product niet gevonden.");
return res.redirect("/products");
}
if (ProductService.productHasListItems(productId, req.user.household_id)) {
req.flash(
"error",
"Dit product staat nog op een boodschappenlijst en kan niet worden verwijderd."
);
return res.redirect(`/products/${productId}/edit`);
}
const result = ProductService.deleteProduct(productId, req.user.household_id);
if (result.changes === 0) {
req.flash("error", "Product niet gevonden.");
return res.redirect("/products");
}
req.flash("success", "Product verwijderd.");
res.redirect("/products");
}
}
module.exports =
new ProductController();