Add ability to manage reconciliation comments for deliveries

Introduce new API endpoints for fetching, creating, and updating reconciliation comments associated with deliveries, including user authentication and authorization checks.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: 95e8aab4-f39f-4b48-aa57-a759ec15ba3d
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1957c339-2757-4d1f-8e92-e9f71a1ce58e/95e8aab4-f39f-4b48-aa57-a759ec15ba3d/BOWXK9F
This commit is contained in:
michaelschal committed 2025-09-10 07:47:03 +00:00
1 parent 8401d22d71
commit 7687b99f45
1 file changed
+157
+157
View File
@@ -42,6 +42,7 @@ import {
insertWeatherSettingsSchema,
insertWebhookBapConfigSchema,
insertAvoirSchema,
insertReconciliationCommentSchema,
users, groups, userGroups, suppliers, orders, deliveries, publicities, publicityParticipations,
customerOrders, nocodbConfig, dlcProducts, tasks, invoiceVerificationCache, dashboardMessages, webhookBapConfig,
avoirs
@@ -1378,6 +1379,162 @@ export async function registerRoutes(app: Express): Promise<Server> {
}
});
// Routes pour les commentaires de rapprochement
// GET - Récupérer les commentaires d'une livraison
app.get('/api/deliveries/:id/reconciliation-comments', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUserWithGroups(req.user.claims ? req.user.claims.sub : req.user.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
const deliveryId = parseInt(req.params.id);
const delivery = await storage.getDelivery(deliveryId);
if (!delivery) {
return res.status(404).json({ message: "Delivery not found" });
}
// Check permissions
if (!hasPermission(user.role, 'deliveries', 'view')) {
return res.status(403).json({ message: "Insufficient permissions" });
}
// Check group access
if (user.role !== 'admin') {
const userGroupIds = user.userGroups?.map((ug: any) => ug.groupId) || [];
if (!userGroupIds.includes(delivery.groupId)) {
return res.status(403).json({ message: "Access denied to this group" });
}
}
const comments = await storage.getReconciliationComments(deliveryId);
res.json(comments);
} catch (error) {
console.error("Error fetching reconciliation comments:", error);
res.status(500).json({ message: "Failed to fetch reconciliation comments" });
}
});
// POST - Créer un nouveau commentaire
app.post('/api/deliveries/:id/reconciliation-comments', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUserWithGroups(req.user.claims ? req.user.claims.sub : req.user.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
const deliveryId = parseInt(req.params.id);
const delivery = await storage.getDelivery(deliveryId);
if (!delivery) {
return res.status(404).json({ message: "Delivery not found" });
}
// Check permissions
if (!hasPermission(user.role, 'deliveries', 'edit')) {
return res.status(403).json({ message: "Insufficient permissions to create comments" });
}
// Check group access
if (user.role !== 'admin') {
const userGroupIds = user.userGroups?.map((ug: any) => ug.groupId) || [];
if (!userGroupIds.includes(delivery.groupId)) {
return res.status(403).json({ message: "Access denied to this group" });
}
}
const commentData = insertReconciliationCommentSchema.parse({
...req.body,
deliveryId,
authorId: user.id,
groupId: delivery.groupId,
});
const comment = await storage.createReconciliationComment(commentData);
res.status(201).json(comment);
} catch (error) {
console.error("Error creating reconciliation comment:", error);
res.status(500).json({ message: "Failed to create reconciliation comment" });
}
});
// PUT - Modifier un commentaire
app.put('/api/reconciliation-comments/:id', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUserWithGroups(req.user.claims ? req.user.claims.sub : req.user.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
const commentId = parseInt(req.params.id);
const comments = await storage.getReconciliationComments(0); // Get all to find the comment
const comment = comments.find(c => c.id === commentId);
if (!comment) {
return res.status(404).json({ message: "Comment not found" });
}
// Check permissions - only author or admin can edit
if (user.role !== 'admin' && comment.authorId !== user.id) {
return res.status(403).json({ message: "Only comment author or admin can edit comments" });
}
// Check group access
if (user.role !== 'admin') {
const userGroupIds = user.userGroups?.map((ug: any) => ug.groupId) || [];
if (!userGroupIds.includes(comment.groupId)) {
return res.status(403).json({ message: "Access denied to this group" });
}
}
const updateData = insertReconciliationCommentSchema.partial().parse(req.body);
const updatedComment = await storage.updateReconciliationComment(commentId, updateData);
res.json(updatedComment);
} catch (error) {
console.error("Error updating reconciliation comment:", error);
res.status(500).json({ message: "Failed to update reconciliation comment" });
}
});
// DELETE - Supprimer un commentaire
app.delete('/api/reconciliation-comments/:id', isAuthenticated, async (req: any, res) => {
try {
const user = await storage.getUserWithGroups(req.user.claims ? req.user.claims.sub : req.user.id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
const commentId = parseInt(req.params.id);
const comments = await storage.getReconciliationComments(0); // Get all to find the comment
const comment = comments.find(c => c.id === commentId);
if (!comment) {
return res.status(404).json({ message: "Comment not found" });
}
// Check permissions - only author or admin can delete
if (user.role !== 'admin' && comment.authorId !== user.id) {
return res.status(403).json({ message: "Only comment author or admin can delete comments" });
}
// Check group access
if (user.role !== 'admin') {
const userGroupIds = user.userGroups?.map((ug: any) => ug.groupId) || [];
if (!userGroupIds.includes(comment.groupId)) {
return res.status(403).json({ message: "Access denied to this group" });
}
}
await storage.deleteReconciliationComment(commentId);
res.json({ message: "Comment deleted successfully" });
} catch (error) {
console.error("Error deleting reconciliation comment:", error);
res.status(500).json({ message: "Failed to delete reconciliation comment" });
}
});
// Route de vérification de facture NocoDB
app.post('/api/deliveries/:id/verify-invoice', isAuthenticated, async (req: any, res) => {
try {