Browse Source

Merge branch 'master' of https://git.c4m.mg/C4M/api-isakafo

# Conflicts:
#	config/databases.js
#	routes/protectedRoute.js
master
valerien 5 months ago
parent
commit
5160c1736f
  1. 51
      controllers/CompartimentController.js
  2. 144
      controllers/CustomersController.js
  3. 82
      controllers/EmplacementController.js
  4. 238
      controllers/FinancesController.js
  5. 41
      controllers/FournisseurController.js
  6. 59
      controllers/ModulesController.js
  7. 147
      controllers/ReservtionController.js
  8. 0
      controllers/SettingsController.js
  9. 58
      controllers/StockController.js
  10. 106
      controllers/TablesController.js
  11. 12
      controllers/TransactionsController.js
  12. 76
      routes/protectedRoute.js

51
controllers/CompartimentController.js

@ -0,0 +1,51 @@
const { pool } = require('../config/databases');
exports.createCompartiment = async (req, res) => {
const {name, capacity, uniter, id_emplacement,} = req.body;
if (!name) {
return res.status(400).json({ message: 'Name are required.' });
} else if (!capacity) {
return res.status(400).json({ message: 'Capacity is required.' });
} else if (!uniter) {
return res.status(400).json({ message: 'Uniter is required.' });
}
// verify if emplacement exists
try {
const [emplacement] = await pool.query('SELECT * FROM emplacements WHERE id = ?', [id_emplacement]);
if (emplacement.length === 0) {
return res.status(404).json({ message: 'Emplacement not found.' });
}
// Insert compartiment
const [result] = await pool.query('INSERT INTO compartiments (name, capacity, uniter, id_emplacement) VALUES (?, ?, ?, ?)', [name, capacity, uniter, id_emplacement]);
res.status(201).json({
message: 'Compartiment created successfully',
compartiment: {
id: result.insertId,
name,
capacity,
uniter,
id_emplacement,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
});
} catch (error) {
console.error(error);
return res.status(500).json({ message: 'Server error while creating compartiment.' });
}
}
exports.getCompartiments = async (req, res) => {
try {
const [rows] = await pool.query('SELECT * FROM compartiments');
res.json(rows);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching compartiments.' });
}
}

144
controllers/CustomersController.js

@ -0,0 +1,144 @@
const { pool } = require('../config/databases');
const { validationResult } = require('express-validator');
// Lister les clients avec recherche et stats
exports.index = async (req, res) => {
const query = req.query.query || '';
try {
let [clients] = query
? await pool.query(
`SELECT * FROM clients WHERE name LIKE ? OR email LIKE ?`,
[`%${query}%`, `%${query}%`]
)
: await db.query(`SELECT * FROM clients`);
const [totalClientsResult] = await pool.query(`SELECT COUNT(*) as total FROM clients`);
const [loyalResult] = await pool.query(`SELECT COUNT(*) as loyal FROM clients WHERE membership IN ('Or', 'Argent')`);
const [bronzeResult] = await pool.query(`SELECT COUNT(*) as bronze FROM clients WHERE membership = 'Bronze'`);
const [argentResult] = await pool.query(`SELECT COUNT(*) as argent FROM clients WHERE membership = 'Argent'`);
const [orResult] = await pool.query(`SELECT COUNT(*) as gold FROM clients WHERE membership = 'Or'`);
const avgSatisfaction = '4.6/5'; // À calculer depuis table avis
const avgCart = '€45'; // À calculer depuis commandes
const fidelityLevels = {
Bronze: {
count: bronzeResult[0].bronze,
benefits: ['5% de réduction', 'Offre anniversaire']
},
Argent: {
count: argentResult[0].argent,
benefits: ['10% de réduction', 'Réservation prioritaire', 'Menu dégustation offert']
},
Or: {
count: orResult[0].gold,
benefits: ['15% de réduction', 'Service VIP', 'Événements exclusifs', 'Livraison gratuite']
}
};
const marketingCampaigns = [
{
name: 'Newsletter hebdomadaire',
description: 'Envoyée tous les vendredis',
subscribers: 1247,
type: 'newsletter'
},
{
name: 'Offre spéciale Saint-Valentin',
description: 'SMS ciblé',
target: 342,
type: 'sms'
}
];
res.json({
searchQuery: query,
clients,
totalClients: totalClientsResult[0].total,
loyalClients: loyalResult[0].loyal,
avgSatisfaction,
avgCart,
fidelityLevels,
marketingCampaigns
});
} catch (error) {
res.status(500).json({ error: 'Erreur serveur', details: error.message });
}
};
// Ajouter un nouveau client avec validation
exports.save = async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty())
return res.status(400).json({ errors: errors.array() });
const { name, email, phone, visits, spent, rating, preferences } = req.body;
let membership = '';
if (visits >= 20 && spent >= 1000000) membership = 'Or';
else if (visits >= 10 && spent >= 500000) membership = 'Argent';
else if (visits >= 10 && spent >= 300000) membership = 'Bronze';
try {
await pool.query(
`INSERT INTO clients (name, email, phone, visits, spent, rating, membership, preferences)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[
name,
email,
phone || '',
visits,
spent,
rating,
membership,
JSON.stringify(preferences || [])
]
);
res.status(201).json({ message: `Client "${name}" ajouté avec succès !` });
} catch (err) {
res.status(500).json({ error: 'Erreur serveur', details: err.message });
}
};
// Afficher les détails d'un client
exports.show = async (req, res) => {
const id = req.params.id;
try {
const [result] = await pool.query(`SELECT * FROM clients WHERE id = ?`, [id]);
if (result.length === 0)
return res.status(404).json({ error: 'Client non trouvé' });
const client = result[0];
res.json({
niveauAdhesion: client.membership,
evaluation: client.rating
});
} catch (err) {
res.status(500).json({ error: 'Erreur serveur', details: err.message });
}
};
// Éditer un client (renvoyer les infos + moyenne des avis)
exports.edit = async (req, res) => {
const clientId = req.params.id;
try {
const [result] = await pool.query(`SELECT * FROM clients WHERE id = ?`, [clientId]);
if (result.length === 0)
return res.status(404).json({ error: 'Client non trouvé' });
const client = result[0];
const [noteResult] = await pool.query(`SELECT AVG(note) as note FROM avis WHERE client_id = ?`, [clientId]);
const evaluation = noteResult[0].note || 0;
res.json({
client,
evaluation
});
} catch (err) {
res.status(500).json({ error: 'Erreur serveur', details: err.message });
}
};

82
controllers/EmplacementController.js

@ -0,0 +1,82 @@
const { pool } = require('../config/databases');
exports.createEmplacement = async (req, res) => {
const { name, type, temperature, capacity } = req.body;
if (!name || !type) {
return res.status(400).json({ message: 'Name and type are required.' });
} else if (!temperature) {
return res.status(400).json({ message: 'Temperature is required.' });
} else if (!capacity) {
return res.status(400).json({ message: 'Capacity is required.' });
}
try {
const [result] = await pool.query('INSERT INTO emplacements (name, type, temperature, capacity) VALUES (?, ?, ?, ?)', [name, type, temperature, capacity]);
res.status(201).json({
message: 'Emplacement created successfully',
emplacement: {
id: result.insertId,
name,
type,
temperature,
capacity,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
});
} catch (error) {
console.error(error);
return res.status(500).json({ message: 'Server error while creating emplacement.' });
}
}
exports.getEmplacements = async (req, res) => {
try {
const [rows] = await pool.query('SELECT * FROM emplacements');
res.json(rows);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching emplacements.' });
}
}
exports.getEmplacementById = async (req, res) => {
const { id } = req.params;
try {
const [rows] = await pool.query('SELECT * FROM emplacements WHERE id = ?', [id]);
if (rows.length === 0) {
return res.status(404).json({ message: 'Emplacement not found.' });
}
res.json(rows[0]);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching emplacement.' });
}
}
exports.updateEmplacement = async (req, res) => {
const { id } = req.params;
const { name, type, temperature, capacity } = req.body;
if (!name || !type || !temperature || !capacity) {
return res.status(400).json({ message: 'All fields are required.' });
}
try {
const [result] = await pool.query('UPDATE emplacements SET name = ?, type = ?, temperature = ?, capacity = ? WHERE id = ?', [name, type, temperature, capacity, id]);
if (result.affectedRows === 0) {
return res.status(404).json({ message: 'Emplacement not found.' });
}
res.json({ message: 'Emplacement updated successfully' });
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while updating emplacement.' });
}
}

238
controllers/FinancesController.js

@ -0,0 +1,238 @@
const { pool } = require('../config/databases');
// GET /finances
const getDashboard = async (req, res) => {
try {
const [payments] = await pool.query(`
SELECT id, description, payment_date AS date_transaction, 'Paiement' AS type_transaction, 'Recette' AS categorie, amount
FROM payments
ORDER BY payment_date DESC
LIMIT 10
`);
const [[{ totalRevenue }]] = await pool.query(`SELECT SUM(amount) AS totalRevenue FROM payments`);
let expenses = [], totalExpenses = 0, depenses_change = 0;
const [expensesTable] = await pool.query(`SHOW TABLES LIKE 'expenses'`);
if (expensesTable.length > 0) {
[expenses] = await db.query(`
SELECT id, description, expense_date AS date_transaction, 'Dépense' AS type_transaction, 'Dépense' AS categorie, amount
FROM expenses
ORDER BY expense_date DESC
LIMIT 10
`);
const [[{ total }]] = await pool.query(`SELECT SUM(amount) AS total FROM expenses`);
totalExpenses = total || 0;
const previousMonthExpenses = 800000;
if (previousMonthExpenses > 0) {
depenses_change = ((totalExpenses - previousMonthExpenses) / previousMonthExpenses) * 100;
}
}
const previousMonthRevenue = 2000000;
const chiffre_affaires_change = (previousMonthRevenue > 0)
? ((totalRevenue - previousMonthRevenue) / previousMonthRevenue) * 100
: 0;
const benefice_net = totalRevenue - totalExpenses;
const benefice_net_marge = totalRevenue > 0 ? (benefice_net / totalRevenue) * 100 : 0;
const tresorerie = benefice_net;
const dashboard_stats = {
chiffre_affaires: totalRevenue,
chiffre_affaires_change,
depenses: totalExpenses,
depenses_change,
benefices: benefice_net,
benefice_net,
benefice_net_marge,
tresorerie,
tresorerie_solde: tresorerie,
total_liabilities: 0
};
const profitLoss = {
revenu_total: totalRevenue,
depense_total: totalExpenses,
benefice_net,
marge: benefice_net_marge
};
const balanceSheet = {
total_assets: 0,
total_liabilities: 0,
total_equity: 0,
net_worth: 0
};
const transactions = [...payments, ...expenses].sort((a, b) =>
new Date(b.date_transaction) - new Date(a.date_transaction)
);
const [[invoiceTable]] = await pool.query(`SHOW TABLES LIKE 'invoices'`);
let invoices = [];
if (invoiceTable) {
[invoices] = await pool.query(`
SELECT id, invoice_number, client_name, invoice_date, status, total_amount
FROM invoices
ORDER BY invoice_date DESC
LIMIT 10
`);
}
res.json({
transactions,
dashboard_stats,
reportDate: new Date().toISOString().slice(0, 10),
profitLoss,
balanceSheet,
invoices
});
} catch (err) {
console.error("Erreur dans getDashboard:", err.message);
res.status(500).json({ error: "Erreur serveur" });
}
};
// POST /finances/invoices
const generateInvoice = async (req, res) => {
const {
invoice_number,
client_name,
client_email,
client_address,
invoice_date,
due_date,
total_amount,
status = 'Draft',
notes
} = req.body;
try {
await pool.query(`
INSERT INTO invoices (invoice_number, client_name, client_email, client_address, invoice_date, due_date, total_amount, status, notes)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
invoice_number.trim(),
client_name.trim(),
client_email?.trim() || null,
client_address.trim(),
invoice_date || new Date(),
due_date || null,
parseFloat(total_amount),
status.trim(),
notes?.trim()
]);
res.status(201).json({ message: 'Facture ajoutée avec succès.' });
} catch (err) {
console.error("Erreur dans generateInvoice:", err.message);
res.status(500).json({ error: err.message });
}
};
// POST /finances/payments
const processPayment = async (req, res) => {
const { invoice_id, payment_date, amount, payment_method, description } = req.body;
const conn = await pool.getConnection();
try {
await conn.beginTransaction();
await conn.query(`
INSERT INTO payments (invoice_id, payment_date, amount, payment_method, description)
VALUES (?, ?, ?, ?, ?)
`, [
invoice_id,
payment_date || new Date(),
parseFloat(amount),
payment_method.trim(),
description.trim()
]);
const [[{ total_amount }]] = await conn.query(`SELECT total_amount FROM invoices WHERE id = ?`, [invoice_id]);
const [[{ total_paid }]] = await conn.query(`SELECT SUM(amount) AS total_paid FROM payments WHERE invoice_id = ?`, [invoice_id]);
let status = 'Partially Paid';
if (Math.abs(total_amount - total_paid) < 0.01) {
status = 'Paid';
}
await conn.query(`UPDATE invoices SET status = ? WHERE id = ?`, [status, invoice_id]);
await conn.query(`
UPDATE balance_sheet_accounts
SET amount = amount + ?
WHERE name = 'Trésorerie' AND account_type = 'Asset'
`, [amount]);
await conn.commit();
res.status(200).json({ message: 'Paiement enregistré avec succès.' });
} catch (err) {
await conn.rollback();
console.error("Erreur dans processPayment:", err.message);
res.status(500).json({ error: err.message });
} finally {
conn.release();
}
};
// GET + POST /finances/taxes
const getTaxes = async (req, res) => {
const [taxes] = await pool.query(`SELECT * FROM taxes ORDER BY name ASC`);
res.json(taxes);
};
const createOrUpdateTax = async (req, res) => {
const { id, name, rate, description, is_active } = req.body;
if (!name || isNaN(rate)) {
return res.status(400).json({ error: 'Nom et taux valides requis.' });
}
try {
if (id) {
await pool.query(`
UPDATE taxes SET name = ?, rate = ?, description = ?, is_active = ?
WHERE id = ?
`, [name.trim(), rate, description?.trim(), is_active ? 1 : 0, id]);
} else {
await pool.query(`
INSERT INTO taxes (name, rate, description, is_active)
VALUES (?, ?, ?, ?)
`, [name.trim(), rate, description?.trim(), is_active ? 1 : 0]);
}
res.json({ message: 'Taxe enregistrée.' });
} catch (err) {
console.error("Erreur dans createOrUpdateTax:", err.message);
res.status(500).json({ error: err.message });
}
};
// DELETE /finances/taxes/:id
const disableTax = async (req, res) => {
const id = parseInt(req.params.id);
if (!id) return res.status(400).json({ error: "ID invalide" });
try {
await pool.query(`UPDATE taxes SET is_active = 0 WHERE id = ?`, [id]);
res.json({ message: 'Taxe désactivée.' });
} catch (err) {
console.error("Erreur dans disableTax:", err.message);
res.status(500).json({ error: err.message });
}
};
module.exports = {
getDashboard,
generateInvoice,
processPayment,
getTaxes,
createOrUpdateTax,
disableTax
};

41
controllers/FournisseurController.js

@ -0,0 +1,41 @@
const { pool } = require('../config/databases');
exports.createFournisseur = async (req, res) => {
const { name, category, contact_person, phone, email, status } = req.body;
if (!name || !category || !contact_person || !phone || !email || !status) {
return res.status(400).json({ message: 'All fields are required.' });
}
try {
const [result] = await pool.query('INSERT INTO fournisseurs (name, category, contact_person, phone, email, status) VALUES(?, ?, ?, ?, ?, ?)', [name, category, contact_person, phone, email, status]);
res.status(201).json({
message: 'Fournisseur created successfully',
fournisseur: {
id: result.insertId,
name,
category,
contact_person,
phone,
email,
status,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
});
} catch (error) {
console.error(error);
return res.status(500).json({ message: 'Server error while creating ingredient.' });
}
}
exports.getFournisseurs = async (req, res) => {
try {
const [rows] = await pool.query('SELECT * FROM fournisseurs');
res.json(rows);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching fournisseurs.' });
}
}

59
controllers/ModulesController.js

@ -0,0 +1,59 @@
const { pool } = require('../config/databases');
// Afficher la liste des modules avec leur état pour un établissement donné
exports.index = async (req, res) => {
try {
const etablissementId = 1; // À remplacer par auth ou token utilisateur
const [modules] = await pool.query(`SELECT * FROM modules`);
const [actifsRaw] = await pool.query(`
SELECT module_id, est_actif
FROM etablissement_modules
WHERE etablissement_id = ?`,
[etablissementId]
);
const actifs = {};
actifsRaw.forEach(row => {
actifs[row.module_id] = !!row.est_actif;
});
res.render('modules/index', { modules, actifs });
} catch (err) {
res.status(500).json({ error: 'Erreur serveur', details: err.message });
}
};
// Activer/désactiver un module (AJAX)
exports.toggle = async (req, res) => {
const { id, actif } = req.body;
const moduleId = parseInt(id, 10);
const etablissementId = 1; // Authentification future ici
try {
const [existing] = await pool.query(
`SELECT id FROM etablissement_modules
WHERE module_id = ? AND etablissement_id = ?`,
[moduleId, etablissementId]
);
if (existing.length > 0) {
await pool.query(
`UPDATE etablissement_modules
SET est_actif = ?
WHERE id = ?`,
[actif ? 1 : 0, existing[0].id]
);
} else {
await pool.query(
`INSERT INTO etablissement_modules (module_id, etablissement_id, est_actif)
VALUES (?, ?, ?)`,
[moduleId, etablissementId, actif ? 1 : 0]
);
}
res.json({ success: true });
} catch (err) {
res.status(500).json({ success: false, error: err.message });
}
};

147
controllers/ReservtionController.js

@ -0,0 +1,147 @@
const reservationModel = require('../models/reservationModel');
const tableModel = require('../models/tableModel');
const invoiceModel = require('../models/invoiceModel');
// Helper pour filtrer selon la période
const filterByPeriod = (reservations, period) => {
const today = new Date();
const todayStr = today.toISOString().slice(0, 10);
return reservations.filter((res) => {
const resDate = new Date(res.date_reservation).toISOString().slice(0, 10);
switch (period) {
case 'aujourdhui':
return resDate === todayStr;
case 'demain':
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
return resDate === tomorrow.toISOString().slice(0, 10);
case 'cette-semaine':
const day = today.getDay();
const diffToMonday = today.getDate() - day + (day === 0 ? -6 : 1);
const monday = new Date(today.setDate(diffToMonday));
const sunday = new Date(monday);
sunday.setDate(monday.getDate() + 6);
return new Date(res.date_reservation) >= monday && new Date(res.date_reservation) <= sunday;
case 'toutes':
default:
return true;
}
});
};
// GET /reservations
const index = async (req, res) => {
const period = req.query.period || 'aujourdhui';
const allReservations = await reservationModel.getAll();
const tables = await tableModel.getAll();
const filteredReservations = filterByPeriod(allReservations, period);
const confirmedReservations = filteredReservations.filter(r => r.statut_reservation === 'Confirmée').length;
const pendingReservations = filteredReservations.filter(r => r.statut_reservation === 'En attente').length;
const estimatedRevenue = filteredReservations.reduce((acc, r) => acc + (parseFloat(r.montant_estime_mga) || 0), 0);
const reservedTables = [...new Set(
filteredReservations
.filter(r => r.type_reservation === 'table' && !['Annulée', 'Terminée'].includes(r.statut_reservation))
.map(r => r.numero_table_chambre)
)].length;
const occupancyRate = tables.length > 0 ? Math.round((reservedTables / tables.length) * 100) : 0;
res.json({
currentPeriod: period,
filteredReservations,
tables,
confirmedReservations,
pendingReservations,
estimatedRevenue,
occupancyRate
});
};
// POST /reservations
const store = async (req, res) => {
try {
const data = req.body;
const reservationId = await reservationModel.insert(data);
if (reservationId) {
const lastInvoice = await invoiceModel.getLast();
let newInvoiceNumber = 'F00001';
if (lastInvoice && lastInvoice.invoice_number.match(/F(\d+)/)) {
const num = parseInt(RegExp.$1);
newInvoiceNumber = 'F' + String(num + 1).padStart(5, '0');
}
await invoiceModel.insert({
invoice_number: newInvoiceNumber,
client_name: data.client_nom,
client_email: data.email || null,
invoice_date: new Date(),
due_date: null,
total_amount: parseFloat(data.montant_estime_mga) || 0,
status: 'Draft',
reservation_id: reservationId,
notes: data.notes_speciales || null
});
}
res.status(201).json({ message: 'Réservation et facture ajoutées avec succès.' });
} catch (err) {
console.error('Erreur dans store():', err.message);
res.status(500).json({ error: err.message });
}
};
// DELETE /reservations/:id
const destroy = async (req, res) => {
const { id } = req.params;
await reservationModel.delete(id);
res.json({ message: 'Réservation supprimée.' });
};
// GET /reservations/:id/edit
const edit = async (req, res) => {
const { id } = req.params;
const reservation = await reservationModel.findById(id);
if (!reservation) {
return res.status(404).json({ error: 'Réservation introuvable.' });
}
res.json({ reservation });
};
// PUT /reservations/:id
const update = async (req, res) => {
const { id } = req.params;
const data = req.body;
if (!data.client_nom || data.client_nom.length < 3) {
return res.status(400).json({ error: 'Nom client invalide.' });
}
// Autres validations manuelles ici si besoin
await reservationModel.update(id, data);
res.json({ message: 'Réservation mise à jour.' });
};
// GET /reservations/create?table=3
const create = (req, res) => {
const tableId = req.query.table;
res.json({ table: tableId });
};
module.exports = {
index,
store,
destroy,
edit,
update,
create
};

0
controllers/SettingsController.js

58
controllers/StockController.js

@ -0,0 +1,58 @@
const { pool } = require('../config/databases');
exports.createIngredient = async (req, res) => {
const { articles, quantity, uniter, price_unit, id_emplacement, id_compartiment } = req.body;
if (!articles || !quantity || !uniter || !price_unit) {
return res.status(400).json({ message: 'All fields are required.' });
}
// verify if compartiment exists
try {
const [compartiment] = await pool.query('SELECT * FROM compartiments WHERE id = ?', [id_compartiment]);
if (compartiment.length === 0) {
return res.status(404).json({ message: 'Compartiment not found.' });
}
// Insert ingredient
const [result] = await pool.query('INSERT INTO stocks (articles, quantity, uniter, price_unit, id_emplacement, id_compartiment) VALUES (?, ?, ?, ?, ?, ?)', [articles, quantity, uniter, price_unit, id_emplacement, id_compartiment]);
res.status(201).json({
message: 'Ingredient created successfully',
ingredient: {
id: result.insertId,
articles,
quantity,
uniter,
price_unit,
id_compartiment,
created_at: new Date().toISOString(),
updated_at: new Date().toISOString()
}
});
} catch (error) {
console.error(error);
return res.status(500).json({ message: 'Server error while creating ingredient.' });
}
}
exports.getIngredientsInventaire = async (req, res) => {
try {
const [rows] = await pool.query('SELECT emplacements.name, stocks.id as stock_id, stocks.articles, stocks.uniter, stocks.quantity, stocks.id_emplacement, stocks.id_compartiment FROM emplacements JOIN stocks ON emplacements.id = stocks.id_emplacement');
res.json(rows);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching ingredients.' });
}
}
exports.getIngredientsEmplacements = async (req, res) => {
try {
const [rows] = await pool.query('SELECT emplacements.name AS emplacement_name, emplacements.id AS emplacement_id, emplacements.type AS emplacement_type, emplacements.temperature, emplacements.capacity AS emplacement_capacity, compartiments.id AS compartiment_id, compartiments.name AS compartiment_name, compartiments.capacity AS compartiment_capacity, compartiments.uniter AS compartiment_uniter, stocks.id AS stock_id, stocks.articles, stocks.quantity, stocks.uniter AS stock_uniter, stocks.price_unit FROM emplacements JOIN compartiments ON emplacements.id = compartiments.id_emplacement JOIN stocks ON compartiments.id = stocks.id_compartiment');
res.json(rows);
} catch (error) {
console.error(error);
res.status(500).json({ message: 'Server error while fetching ingredients.' });
}
}

106
controllers/TablesController.js

@ -0,0 +1,106 @@
const { pool } = require('../config/databases');
exports.index = async (req, res) => {
try {
const [tables] = await pool.query('SELECT * FROM tables');
res.render('tables/index', { tables });
} catch (err) {
res.status(500).send('Erreur serveur : ' + err.message);
}
};
// Affiche formulaire création (rendu simple, adapter selon moteur de vue)
exports.create = (req, res) => {
res.render('tables/create');
};
// Enregistre nouvelle table
exports.store = async (req, res) => {
const { numero_table, capacite, statut_actuel } = req.body;
try {
await pool.query(
`INSERT INTO tables (numero_table, capacite, statut_actuel, id_reservation_actuelle)
VALUES (?, ?, ?, NULL)`,
[numero_table, capacite, statut_actuel]
);
res.redirect('/tables?success=Table ajoutée avec succès.');
} catch (err) {
// En cas d'erreur, tu peux passer l'erreur en query string ou gérer autrement
res.redirect('/tables/create?error=' + encodeURIComponent(err.message));
}
};
// Affiche formulaire édition
exports.edit = async (req, res) => {
const id = req.params.id;
try {
const [rows] = await pool.query('SELECT * FROM tables WHERE id = ?', [id]);
if (rows.length === 0) {
return res.status(404).send('Table non trouvée');
}
res.render('tables/edit', { table: rows[0] });
} catch (err) {
res.status(500).send('Erreur serveur : ' + err.message);
}
};
// Met à jour une table
exports.update = async (req, res) => {
const id = req.params.id;
const data = req.body;
try {
// Mettre à jour la table
const [result] = await pool.query(
`UPDATE tables SET numero_table = ?, capacite = ?, statut_actuel = ? WHERE id = ?`,
[data.numero_table, data.capacite, data.statut_actuel, id]
);
res.redirect('/tables?success=Table modifiée avec succès.');
} catch (err) {
res.redirect(`/tables/${id}/edit?error=` + encodeURIComponent(err.message));
}
};
// Supprimer une table
exports.delete = async (req, res) => {
const id = req.params.id;
try {
await pool.query('DELETE FROM tables WHERE id = ?', [id]);
res.redirect('/tables?success=Table supprimée.');
} catch (err) {
res.status(500).send('Erreur serveur : ' + err.message);
}
};
// Afficher détails JSON d'une table + client réservation en cours
exports.show = async (req, res) => {
const id = req.params.id;
try {
const [tables] = await pool.query('SELECT * FROM tables WHERE id = ?', [id]);
if (tables.length === 0) {
return res.status(404).json({ error: 'Table non trouvée' });
}
const table = tables[0];
const [reservations] = await pool.query(`
SELECT client_nom FROM reservations
WHERE type_reservation = 'table'
AND numero_table_chambre = ?
AND statut_reservation IN ('Confirmée', 'En attente')
LIMIT 1
`, [table.numero_table]);
const reservation = reservations.length > 0 ? reservations[0] : {};
res.json({
capacite: table.capacite,
details: table.details || 'N/A',
statut_actuel: table.statut_actuel,
client_nom: reservation.client_nom || null,
});
} catch (err) {
res.status(500).json({ error: 'Erreur serveur', details: err.message });
}
};

12
controllers/TransactionsController.js

@ -0,0 +1,12 @@
const { pool } = require('../config/databases');
exports.index = async (req, res) => {
try {
const [transactions] = await pool.query(
'SELECT * FROM transactions ORDER BY date_transaction DESC'
);
res.render('transactions/transactions_content', { transactions });
} catch (err) {
res.status(500).send('Erreur serveur : ' + err.message);
}
};

76
routes/protectedRoute.js

@ -2,11 +2,32 @@ const express = require('express');
const authMiddleware = require('../middleware/authMiddleware');
const userController = require('../controllers/UserController');
const staffController = require('../controllers/staffsController');
const emplacementController = require('../controllers/emplacementController');
const compartimentController = require('../controllers/compartimentController');
const stockController = require('../controllers/stockController');
const fournisseurController = require('../controllers/FournisseurController');
const reservationController = require('../controllers/ReservationController');
const financesController = require('../controllers/FinancesController');
const CustomersController = require('../controllers/CustomersController');
const SettingsController = require('../controllers/SettingsController');
const ModulesController = require('../controllers/ModulesController');
const TablesController = require('../controllers/TablesController');
const TransactionsController = require('../controllers/TransactionsController');
const router = express.Router();
router.get('/profile', authMiddleware(), userController.getProfile);
router.get('/admin', authMiddleware('admin'), userController.getAdminPage);
router.post('/create', authMiddleware('admin'), userController.createUser);
router.post('/create/emplacement', authMiddleware(), emplacementController.createEmplacement);
router.get('/emplacements', authMiddleware(), emplacementController.getEmplacements);
router.get('/emplacement/:id', authMiddleware(), emplacementController.getEmplacementById);
router.get('/compartiments', authMiddleware(), compartimentController.getCompartiments);
router.post('/create/compartiment', authMiddleware(), compartimentController.createCompartiment);
router.post('/create/ingredient', authMiddleware(), stockController.createIngredient);
router.get('/ingredients/inventaire', authMiddleware(), stockController.getIngredientsInventaire);
router.get('/ingredients/emplacement', authMiddleware(), stockController.getIngredientsEmplacements);
router.post('/create/fournisseur', authMiddleware(), fournisseurController.createFournisseur);
router.get('/fournisseurs', authMiddleware(), fournisseurController.getFournisseurs);
router.get('/staffs', authMiddleware(), staffController.index);
router.get('/staffs/create', authMiddleware('admin'), staffController.create);
@ -15,4 +36,59 @@ router.get('/staffs/:id/edit', authMiddleware(), staffController.edit);
router.post('/staffs/:id/update', authMiddleware('admin'), staffController.update);
router.get('/staffs/:id/contact', authMiddleware(), staffController.contact);
router.get('/staffs/:employeId/statut/:date', authMiddleware(), staffController.calculerStatutEmploye);
router.get('/reservations', authMiddleware(), reservationController.index); // équivalent de $routes->get('/reservations', ...)
router.get('/reservations/ajax', authMiddleware(), reservationController.getReservationsAjax); // si cette méthode existe
router.get('/reservations/create', authMiddleware(), reservationController.create);
router.post('/reservations/store', authMiddleware(), reservationController.store);
router.get('/reservations/:id/edit', authMiddleware(), reservationController.edit);
router.put('/reservations/:id', authMiddleware(), reservationController.update);
router.delete('/reservations/:id', authMiddleware(), reservationController.destroy);
router.get('/finances', authMiddleware(), financesController.getDashboard);
router.post('/finances/invoices', authMiddleware(), financesController.generateInvoice);
router.post('/finances/payments', authMiddleware(), financesController.processPayment);
router.get('/finances/taxes', authMiddleware(), financesController.getTaxes);
router.post('/finances/taxes', authMiddleware(), financesController.createOrUpdateTax);
router.delete('/finances/taxes/:id', authMiddleware(), financesController.disableTax);
router.get('/customers',authMiddleware(), CustomersController.index); // Liste des clients
router.get('/customers/new', (req, res) => res.send('Formulaire nouveau client')); // Optionnel
router.post('/customers/save', authMiddleware(), CustomersController.save); // Enregistrer un client
router.get('/customers/:id',authMiddleware(), CustomersController.show);
router.get('customers/:id/edit', authMiddleware(), CustomersController.edit);
router.put('customers/:id/uptade',authMiddleware(), CustomersController.update);
router.delete('customers/:id/delete',authMiddleware(), CustomersController.delete);
router.get('/settings', authMiddleware(), SettingsController.getSettingsPage);
router.post('/settings/restaurant', authMiddleware(), SettingsController.updateRestaurantInfo);
router.post('/settings/opening-hours', authMiddleware(), SettingsController.updateOpeningHours);
router.post('/settings/notifications', authMiddleware(), SettingsController.updateNotifications);
router.get('/settings/users/new', authMiddleware(), SettingsController.addUser);
router.post('/settings/users', authMiddleware(), SettingsController.saveUser);
router.get('/settings/users/:id/edit', authMiddleware(), SettingsController.editUser);
router.put('/settings/users/:id', authMiddleware(), SettingsController.updateUser);
router.delete('/settings/users/:id', authMiddleware(), SettingsController.deleteUser);
router.post('/settings/change-password', authMiddleware(), SettingsController.changePassword);
router.post('/settings/two-factor', authMiddleware(), SettingsController.toggleTwoFactorAuth);
router.get('/settings/integrations/booking', authMiddleware(), SettingsController.connectBooking);
router.get('/settings/integrations/quickbooks', authMiddleware(), SettingsController.connectQuickbooks);
router.get('/settings/integrations/stripe', authMiddleware(), SettingsController.connectStripe);
router.get('/settings/modules', authMiddleware(), SettingsController.getModules);
router.get('/modules', authMiddleware(), ModulesController.index);
router.post('/modules/toggle', authMiddleware(), ModulesController.toggle);
router.get('/tables', authMiddleware(), TablesController.index);
router.get('/tables/create', authMiddleware(), TablesController.create);
router.post('/tables', authMiddleware(), TablesController.store);
router.get('/tables/:id/edit', authMiddleware(), TablesController.edit);
router.post('/tables/:id/update', authMiddleware(), TablesController.update);
router.post('/tables/:id/delete', authMiddleware(), TablesController.delete);
router.get('/tables/:id', authMiddleware(), TablesController.show);
router.get('/transactions', authMiddleware(), TransactionsController.index);
module.exports = router;

Loading…
Cancel
Save