216 lines
6.7 KiB
JavaScript
216 lines
6.7 KiB
JavaScript
const ProductService =
|
|
require("../services/ProductService");
|
|
|
|
const CategoryService = require("../services/CategoryService");
|
|
|
|
const parseCsv = require("../utils/parseCsv");
|
|
|
|
class ProductController {
|
|
|
|
|
|
index(req, res) {
|
|
|
|
const products =
|
|
ProductService.getProducts(req.user.household_id);
|
|
|
|
const categories = CategoryService.getCategories(req.user.household_id);
|
|
|
|
res.render(
|
|
"products/index",
|
|
{
|
|
title:"Producten",
|
|
products,
|
|
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(); |