diff --git a/attached_assets/{FB17DA62-CEC3-42D0-968D-5A320AC04471}_1755088564042.png b/attached_assets/{FB17DA62-CEC3-42D0-968D-5A320AC04471}_1755088564042.png new file mode 100644 index 0000000..e84b22d Binary files /dev/null and b/attached_assets/{FB17DA62-CEC3-42D0-968D-5A320AC04471}_1755088564042.png differ diff --git a/client/src/pages/DlcPage.tsx b/client/src/pages/DlcPage.tsx index 708d8e0..b855015 100644 --- a/client/src/pages/DlcPage.tsx +++ b/client/src/pages/DlcPage.tsx @@ -442,7 +442,7 @@ export default function DlcPage() { } }; - const filteredProducts = dlcProducts.filter(product => { + const filteredProducts = (dlcProducts || []).filter(product => { if (searchTerm) { return product.productName.toLowerCase().includes(searchTerm.toLowerCase()) || (product.supplier?.name && product.supplier.name.toLowerCase().includes(searchTerm.toLowerCase())); diff --git a/cookies.txt b/cookies.txt index fec352d..ab83372 100644 --- a/cookies.txt +++ b/cookies.txt @@ -2,4 +2,4 @@ # https://curl.se/docs/http-cookies.html # This file was generated by libcurl! Edit at your own risk. -#HttpOnly_localhost FALSE / FALSE 1755174893 connect.sid s%3AnBdh-Dk3_lel7Iwxh8gfP8z9NpAO6ksl.nU8o8o7MiYpWRYfCNtxnZrgrQwhlUHQqUbUPQXD7uMI +#HttpOnly_localhost FALSE / FALSE 1755175240 connect.sid s%3AeEPGIwIyDfv0Lv1yl_mNnpvEfiTbtG2U.fIbC09urP9gGafY%2BLayxvJMSElehNNST%2BPA9zJDe%2Bx8 diff --git a/server/routes.ts b/server/routes.ts index cadd1cc..35d04a0 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -958,6 +958,488 @@ export async function registerRoutes(app: Express): Promise { } }); + // DLC Products routes + app.get('/api/dlc-products', 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 { storeId, status, supplierId } = req.query; + let groupIds: number[] | undefined; + + if (user.role === 'admin') { + groupIds = storeId ? [parseInt(storeId as string)] : undefined; + } else { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (storeId && userGroupIds.includes(parseInt(storeId as string))) { + groupIds = [parseInt(storeId as string)]; + } else { + groupIds = userGroupIds; + } + } + + const filters: any = {}; + if (status && status !== 'all') filters.status = status as string; + if (supplierId && supplierId !== 'all') filters.supplierId = parseInt(supplierId as string); + + console.log('DLC Products API called with:', { groupIds, filters, userRole: user.role }); + const dlcProducts = await storage.getDlcProducts(groupIds, filters); + console.log('DLC Products returned:', dlcProducts.length, 'items'); + res.json(dlcProducts); + } catch (error) { + console.error("Error fetching DLC products:", error); + res.status(500).json([]); + } + }); + + app.get('/api/dlc-products/stats', 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 { storeId } = req.query; + let groupIds: number[] | undefined; + + if (user.role === 'admin') { + groupIds = storeId ? [parseInt(storeId as string)] : undefined; + } else { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (storeId && userGroupIds.includes(parseInt(storeId as string))) { + groupIds = [parseInt(storeId as string)]; + } else { + groupIds = userGroupIds; + } + } + + const stats = await storage.getDlcStats(groupIds); + res.json(stats); + } catch (error) { + console.error("Error fetching DLC stats:", error); + res.status(500).json({ active: 0, expiringSoon: 0, expired: 0 }); + } + }); + + app.get('/api/dlc-products/: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 id = parseInt(req.params.id); + const dlcProduct = await storage.getDlcProduct(id); + + if (!dlcProduct) { + return res.status(404).json({ message: "DLC Product not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(dlcProduct.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + res.json(dlcProduct); + } catch (error) { + console.error("Error fetching DLC product:", error); + res.status(500).json({ message: "Failed to fetch DLC product" }); + } + }); + + app.post('/api/dlc-products', 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 data = { + ...req.body, + createdBy: user.id, + }; + + // Check if user has access to the group + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(data.groupId)) { + return res.status(403).json({ message: "Access denied to this group" }); + } + } + + const dlcProduct = await storage.createDlcProduct(data); + res.json(dlcProduct); + } catch (error) { + console.error("Error creating DLC product:", error); + res.status(500).json({ message: "Failed to create DLC product" }); + } + }); + + app.put('/api/dlc-products/: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 id = parseInt(req.params.id); + const dlcProduct = await storage.getDlcProduct(id); + + if (!dlcProduct) { + return res.status(404).json({ message: "DLC Product not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(dlcProduct.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + const updatedProduct = await storage.updateDlcProduct(id, req.body); + res.json(updatedProduct); + } catch (error) { + console.error("Error updating DLC product:", error); + res.status(500).json({ message: "Failed to update DLC product" }); + } + }); + + app.delete('/api/dlc-products/: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 id = parseInt(req.params.id); + const dlcProduct = await storage.getDlcProduct(id); + + if (!dlcProduct) { + return res.status(404).json({ message: "DLC Product not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(dlcProduct.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + await storage.deleteDlcProduct(id); + res.json({ message: "DLC Product deleted successfully" }); + } catch (error) { + console.error("Error deleting DLC product:", error); + res.status(500).json({ message: "Failed to delete DLC product" }); + } + }); + + app.post('/api/dlc-products/:id/validate', 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 id = parseInt(req.params.id); + const dlcProduct = await storage.getDlcProduct(id); + + if (!dlcProduct) { + return res.status(404).json({ message: "DLC Product not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(dlcProduct.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + const validatedProduct = await storage.validateDlcProduct(id, user.id); + res.json(validatedProduct); + } catch (error) { + console.error("Error validating DLC product:", error); + res.status(500).json({ message: "Failed to validate DLC product" }); + } + }); + + // Tasks routes + app.get('/api/tasks', 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 { storeId } = req.query; + let groupIds: number[] | undefined; + + if (user.role === 'admin') { + groupIds = storeId ? [parseInt(storeId as string)] : undefined; + } else { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (storeId && userGroupIds.includes(parseInt(storeId as string))) { + groupIds = [parseInt(storeId as string)]; + } else { + groupIds = userGroupIds; + } + } + + console.log('Tasks API called with:', { groupIds, userRole: user.role }); + const tasks = await storage.getTasks(groupIds); + console.log('Tasks returned:', tasks.length, 'items'); + res.json(tasks); + } catch (error) { + console.error("Error fetching tasks:", error); + res.status(500).json([]); + } + }); + + app.post('/api/tasks', 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 data = { + ...req.body, + createdBy: user.id, + }; + + // Check if user has access to the group + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(data.groupId)) { + return res.status(403).json({ message: "Access denied to this group" }); + } + } + + const task = await storage.createTask(data); + res.json(task); + } catch (error) { + console.error("Error creating task:", error); + res.status(500).json({ message: "Failed to create task" }); + } + }); + + app.put('/api/tasks/: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 id = parseInt(req.params.id); + const task = await storage.getTask(id); + + if (!task) { + return res.status(404).json({ message: "Task not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(task.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + const updatedTask = await storage.updateTask(id, req.body); + res.json(updatedTask); + } catch (error) { + console.error("Error updating task:", error); + res.status(500).json({ message: "Failed to update task" }); + } + }); + + app.delete('/api/tasks/: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 id = parseInt(req.params.id); + const task = await storage.getTask(id); + + if (!task) { + return res.status(404).json({ message: "Task not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(task.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + await storage.deleteTask(id); + res.json({ message: "Task deleted successfully" }); + } catch (error) { + console.error("Error deleting task:", error); + res.status(500).json({ message: "Failed to delete task" }); + } + }); + + app.post('/api/tasks/:id/complete', 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 id = parseInt(req.params.id); + const task = await storage.getTask(id); + + if (!task) { + return res.status(404).json({ message: "Task not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(task.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + await storage.completeTask(id, user.id); + res.json({ message: "Task completed successfully" }); + } catch (error) { + console.error("Error completing task:", error); + res.status(500).json({ message: "Failed to complete task" }); + } + }); + + // Customer Orders routes + app.get('/api/customer-orders', 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 { storeId } = req.query; + let groupIds: number[] | undefined; + + if (user.role === 'admin') { + groupIds = storeId ? [parseInt(storeId as string)] : undefined; + } else { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (storeId && userGroupIds.includes(parseInt(storeId as string))) { + groupIds = [parseInt(storeId as string)]; + } else { + groupIds = userGroupIds; + } + } + + console.log('Customer Orders API called with:', { groupIds, userRole: user.role }); + const customerOrders = await storage.getCustomerOrders(groupIds); + console.log('Customer Orders returned:', customerOrders.length, 'items'); + res.json(customerOrders); + } catch (error) { + console.error("Error fetching customer orders:", error); + res.status(500).json([]); + } + }); + + app.post('/api/customer-orders', 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 data = { + ...req.body, + createdBy: user.id, + }; + + // Check if user has access to the group + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(data.groupId)) { + return res.status(403).json({ message: "Access denied to this group" }); + } + } + + const customerOrder = await storage.createCustomerOrder(data); + res.json(customerOrder); + } catch (error) { + console.error("Error creating customer order:", error); + res.status(500).json({ message: "Failed to create customer order" }); + } + }); + + app.put('/api/customer-orders/: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 id = parseInt(req.params.id); + const customerOrder = await storage.getCustomerOrder(id); + + if (!customerOrder) { + return res.status(404).json({ message: "Customer order not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(customerOrder.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + const updatedOrder = await storage.updateCustomerOrder(id, req.body); + res.json(updatedOrder); + } catch (error) { + console.error("Error updating customer order:", error); + res.status(500).json({ message: "Failed to update customer order" }); + } + }); + + app.delete('/api/customer-orders/: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 id = parseInt(req.params.id); + const customerOrder = await storage.getCustomerOrder(id); + + if (!customerOrder) { + return res.status(404).json({ message: "Customer order not found" }); + } + + // Check permissions + if (user.role !== 'admin') { + const userGroupIds = user.userGroups.map(ug => ug.groupId); + if (!userGroupIds.includes(customerOrder.groupId)) { + return res.status(403).json({ message: "Access denied" }); + } + } + + await storage.deleteCustomerOrder(id); + res.json({ message: "Customer order deleted successfully" }); + } catch (error) { + console.error("Error deleting customer order:", error); + res.status(500).json({ message: "Failed to delete customer order" }); + } + }); + // Statistics routes app.get('/api/stats/monthly', isAuthenticated, async (req: any, res) => { try { diff --git a/server/storage.ts b/server/storage.ts index 0233bfc..8e7313b 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -1464,8 +1464,14 @@ export class MemStorage implements IStorage { async getPublicityParticipations(): Promise { return []; } async setPublicityParticipations(): Promise {} - async getCustomerOrders(): Promise { - return Array.from(this.customerOrders.values()).map(order => ({ + async getCustomerOrders(groupIds?: number[]): Promise { + let orders = Array.from(this.customerOrders.values()); + + if (groupIds && groupIds.length > 0) { + orders = orders.filter(order => groupIds.includes(order.groupId)); + } + + return orders.map(order => ({ ...order, supplier: this.suppliers.get(order.supplierId)!, group: this.groups.get(order.groupId)!, @@ -1515,8 +1521,23 @@ export class MemStorage implements IStorage { this.customerOrders.delete(id); } - async getDlcProducts(): Promise { - return Array.from(this.dlcProducts.values()).map(product => ({ + async getDlcProducts(groupIds?: number[], filters?: { status?: string; supplierId?: number; }): Promise { + let products = Array.from(this.dlcProducts.values()); + + if (groupIds && groupIds.length > 0) { + products = products.filter(product => groupIds.includes(product.groupId)); + } + + if (filters) { + if (filters.status) { + products = products.filter(product => product.status === filters.status); + } + if (filters.supplierId) { + products = products.filter(product => product.supplierId === filters.supplierId); + } + } + + return products.map(product => ({ ...product, supplier: this.suppliers.get(product.supplierId)!, group: this.groups.get(product.groupId)!, @@ -1580,12 +1601,17 @@ export class MemStorage implements IStorage { return { ...updatedProduct, dlcDate: new Date(updatedProduct.expiryDate) } as DlcProductFrontend; } - async getDlcStats(): Promise<{ active: number; expiringSoon: number; expired: number; }> { + async getDlcStats(groupIds?: number[]): Promise<{ active: number; expiringSoon: number; expired: number; }> { const today = new Date(); const alertDate = new Date(); alertDate.setDate(today.getDate() + 15); - const products = Array.from(this.dlcProducts.values()); + let products = Array.from(this.dlcProducts.values()); + + if (groupIds && groupIds.length > 0) { + products = products.filter(product => groupIds.includes(product.groupId)); + } + return { active: products.filter(p => new Date(p.expiryDate) > today).length, expiringSoon: products.filter(p => { @@ -1596,8 +1622,14 @@ export class MemStorage implements IStorage { }; } - async getTasks(): Promise { - return Array.from(this.tasks.values()).map(task => ({ + async getTasks(groupIds?: number[]): Promise { + let tasks = Array.from(this.tasks.values()); + + if (groupIds && groupIds.length > 0) { + tasks = tasks.filter(task => groupIds.includes(task.groupId)); + } + + return tasks.map(task => ({ ...task, group: this.groups.get(task.groupId)!, creator: this.users.get(task.createdBy)! @@ -1784,6 +1816,14 @@ export class MemStorage implements IStorage { } } -// Use MemStorage in development, DatabaseStorage in production -const isProduction = process.env.NODE_ENV === 'production'; -export const storage: IStorage = isProduction ? new DatabaseStorage() : new MemStorage(); \ No newline at end of file +// FORCE: Use DatabaseStorage to see real production data +console.log('🔗 Database initialization:', { + NODE_ENV: process.env.NODE_ENV, + isProduction: process.env.NODE_ENV === 'production', + hasDbUrl: !!process.env.DATABASE_URL, + dbHost: process.env.DATABASE_URL?.split('@')[1]?.split('/')[0] || 'unknown' +}); + +// Force DatabaseStorage for real data access +export const storage: IStorage = new DatabaseStorage(); +console.log('✅ Using DatabaseStorage (real PostgreSQL data)'); \ No newline at end of file