Versie 1.0
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
const CategoryService = require("../services/CategoryService");
|
||||
|
||||
|
||||
class CategoryController {
|
||||
|
||||
|
||||
index(req, res) {
|
||||
|
||||
res.render("categories/index", {
|
||||
title: "Categorieën",
|
||||
categories: CategoryService.getCategories()
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
editForm(req, res) {
|
||||
const categoryId = Number.parseInt(req.params.id, 10);
|
||||
const category = Number.isInteger(categoryId)
|
||||
? CategoryService.getCategory(categoryId)
|
||||
: null;
|
||||
|
||||
if (!category) {
|
||||
req.flash("error", "Categorie niet gevonden.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
res.render("categories/edit", {
|
||||
title: "Categorie wijzigen",
|
||||
category
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
create(req, res) {
|
||||
const name = (req.body.name || "").trim();
|
||||
const icon = (req.body.icon || "").trim();
|
||||
|
||||
if (!name) {
|
||||
req.flash("error", "Geef een categorienaam op.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
CategoryService.createCategory({ name, icon });
|
||||
req.flash("success", "Categorie toegevoegd.");
|
||||
res.redirect("/categories");
|
||||
}
|
||||
|
||||
|
||||
update(req, res) {
|
||||
const categoryId = Number.parseInt(req.params.id, 10);
|
||||
const name = (req.body.name || "").trim();
|
||||
const icon = (req.body.icon || "").trim();
|
||||
|
||||
if (!Number.isInteger(categoryId) || !name) {
|
||||
req.flash("error", "Geef een geldige categorienaam op.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
const result = CategoryService.updateCategory(categoryId, { name, icon });
|
||||
|
||||
if (result.changes === 0) {
|
||||
req.flash("error", "Categorie niet gevonden.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
req.flash("success", "Categorie gewijzigd.");
|
||||
res.redirect("/categories");
|
||||
}
|
||||
|
||||
|
||||
remove(req, res) {
|
||||
const categoryId = Number.parseInt(req.params.id, 10);
|
||||
|
||||
if (!Number.isInteger(categoryId)) {
|
||||
req.flash("error", "Categorie niet gevonden.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
if (CategoryService.categoryHasProducts(categoryId)) {
|
||||
req.flash(
|
||||
"error",
|
||||
"Deze categorie is nog aan producten gekoppeld en kan niet worden verwijderd."
|
||||
);
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
const result = CategoryService.deleteCategory(categoryId);
|
||||
|
||||
if (result.changes === 0) {
|
||||
req.flash("error", "Categorie niet gevonden.");
|
||||
return res.redirect("/categories");
|
||||
}
|
||||
|
||||
req.flash("success", "Categorie verwijderd.");
|
||||
res.redirect("/categories");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
module.exports = new CategoryController();
|
||||
@@ -2,6 +2,7 @@ const ProductService =
|
||||
require("../services/ProductService");
|
||||
|
||||
const db = require("../config/database");
|
||||
const parseCsv = require("../utils/parseCsv");
|
||||
|
||||
class ProductController {
|
||||
|
||||
@@ -48,6 +49,156 @@ class ProductController {
|
||||
}
|
||||
|
||||
|
||||
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 = db.prepare("SELECT id, name FROM categories").all();
|
||||
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()
|
||||
});
|
||||
});
|
||||
|
||||
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)
|
||||
: null;
|
||||
|
||||
if (!product) {
|
||||
req.flash("error", "Product niet gevonden.");
|
||||
return res.redirect("/products");
|
||||
}
|
||||
|
||||
const categories = db.prepare(
|
||||
"SELECT * FROM categories ORDER BY name"
|
||||
).all();
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
const result = ProductService.updateProduct(productId, {
|
||||
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.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);
|
||||
|
||||
if (result.changes === 0) {
|
||||
req.flash("error", "Product niet gevonden.");
|
||||
return res.redirect("/products");
|
||||
}
|
||||
|
||||
req.flash("success", "Product verwijderd.");
|
||||
res.redirect("/products");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user