import type { Express } from "express"; import { createServer, type Server } from "http"; import { storage } from "./storage"; import { insertProductSchema, insertStockMovementSchema, insertDocumentSchema } from "@shared/schema"; import { z } from "zod"; export async function registerRoutes(app: Express): Promise { // Products app.get("/api/products", async (req, res) => { try { const products = await storage.getProducts(); res.json(products); } catch (error) { res.status(500).json({ message: "Failed to fetch products" }); } }); app.get("/api/products/search", async (req, res) => { try { const query = req.query.q as string; if (!query) { return res.status(400).json({ message: "Search query is required" }); } const products = await storage.searchProducts(query); res.json(products); } catch (error) { res.status(500).json({ message: "Failed to search products" }); } }); app.get("/api/products/low-stock", async (req, res) => { try { const products = await storage.getLowStockProducts(); res.json(products); } catch (error) { res.status(500).json({ message: "Failed to fetch low stock products" }); } }); app.get("/api/products/out-of-stock", async (req, res) => { try { const products = await storage.getOutOfStockProducts(); res.json(products); } catch (error) { res.status(500).json({ message: "Failed to fetch out of stock products" }); } }); app.get("/api/products/:id", async (req, res) => { try { const product = await storage.getProduct(req.params.id); if (!product) { return res.status(404).json({ message: "Product not found" }); } res.json(product); } catch (error) { res.status(500).json({ message: "Failed to fetch product" }); } }); app.post("/api/products", async (req, res) => { try { const productData = insertProductSchema.parse(req.body); const product = await storage.createProduct(productData); res.status(201).json(product); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid product data", errors: error.errors }); } res.status(500).json({ message: "Failed to create product" }); } }); app.patch("/api/products/:id", async (req, res) => { try { const updates = insertProductSchema.partial().parse(req.body); const product = await storage.updateProduct(req.params.id, updates); if (!product) { return res.status(404).json({ message: "Product not found" }); } res.json(product); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid product data", errors: error.errors }); } res.status(500).json({ message: "Failed to update product" }); } }); app.delete("/api/products/:id", async (req, res) => { try { const deleted = await storage.deleteProduct(req.params.id); if (!deleted) { return res.status(404).json({ message: "Product not found" }); } res.status(204).send(); } catch (error) { res.status(500).json({ message: "Failed to delete product" }); } }); // Stock movements app.get("/api/stock-movements", async (req, res) => { try { const productId = req.query.productId as string; const movements = await storage.getStockMovements(productId); res.json(movements); } catch (error) { res.status(500).json({ message: "Failed to fetch stock movements" }); } }); app.post("/api/stock-movements", async (req, res) => { try { const movementData = insertStockMovementSchema.parse(req.body); const movement = await storage.createStockMovement(movementData); res.status(201).json(movement); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid stock movement data", errors: error.errors }); } res.status(500).json({ message: "Failed to create stock movement" }); } }); // Documents app.get("/api/documents", async (req, res) => { try { const documents = await storage.getDocuments(); res.json(documents); } catch (error) { res.status(500).json({ message: "Failed to fetch documents" }); } }); app.get("/api/documents/:id", async (req, res) => { try { const document = await storage.getDocument(req.params.id); if (!document) { return res.status(404).json({ message: "Document not found" }); } res.json(document); } catch (error) { res.status(500).json({ message: "Failed to fetch document" }); } }); app.post("/api/documents", async (req, res) => { try { const documentData = insertDocumentSchema.parse(req.body); const document = await storage.createDocument(documentData); res.status(201).json(document); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid document data", errors: error.errors }); } res.status(500).json({ message: "Failed to create document" }); } }); app.patch("/api/documents/:id", async (req, res) => { try { const updates = insertDocumentSchema.partial().parse(req.body); const document = await storage.updateDocument(req.params.id, updates); if (!document) { return res.status(404).json({ message: "Document not found" }); } res.json(document); } catch (error) { if (error instanceof z.ZodError) { return res.status(400).json({ message: "Invalid document data", errors: error.errors }); } res.status(500).json({ message: "Failed to update document" }); } }); // Generate PDF document app.get("/api/documents/:id/pdf", async (req, res) => { try { const document = await storage.getDocument(req.params.id); if (!document) { return res.status(404).json({ message: "Document not found" }); } // Simple PDF generation for now - in production would use proper PDF library const pdfContent = ` Document: ${document.title} Type: ${document.type} Number: ${document.documentNumber} Status: ${document.status} Created: ${document.createdAt} Content: ${JSON.stringify(document.content, null, 2)} `; res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${document.documentNumber}.pdf"`); res.send(pdfContent); } catch (error) { res.status(500).json({ message: "Failed to generate PDF" }); } }); // Notifications app.get("/api/notifications", async (req, res) => { try { const notifications = await storage.getNotifications(); res.json(notifications); } catch (error) { res.status(500).json({ message: "Failed to fetch notifications" }); } }); app.get("/api/notifications/unread-count", async (req, res) => { try { const count = await storage.getUnreadNotificationCount(); res.json({ count }); } catch (error) { res.status(500).json({ message: "Failed to fetch notification count" }); } }); app.patch("/api/notifications/:id/read", async (req, res) => { try { const success = await storage.markNotificationAsRead(req.params.id); if (!success) { return res.status(404).json({ message: "Notification not found" }); } res.status(204).send(); } catch (error) { res.status(500).json({ message: "Failed to mark notification as read" }); } }); // Dashboard stats app.get("/api/dashboard/stats", async (req, res) => { try { const products = await storage.getProducts(); const lowStockProducts = await storage.getLowStockProducts(); const outOfStockProducts = await storage.getOutOfStockProducts(); const stats = { totalItems: products.length, inStockItems: products.filter(p => p.currentStock > p.minThreshold).length, lowStockItems: lowStockProducts.length, outOfStockItems: outOfStockProducts.length, }; res.json(stats); } catch (error) { res.status(500).json({ message: "Failed to fetch dashboard stats" }); } }); const httpServer = createServer(app); return httpServer; }