Files
wareApp/server/routes.ts

259 lines
8.3 KiB
TypeScript

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<Server> {
// 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;
}