Files
wareApp/server/storage.ts

350 lines
10 KiB
TypeScript

import {
type Product,
type InsertProduct,
type StockMovement,
type InsertStockMovement,
type Document,
type InsertDocument,
type Order,
type InsertOrder,
type Notification,
type InsertNotification
} from "@shared/schema";
import { randomUUID } from "crypto";
export interface IStorage {
// Products
getProducts(): Promise<Product[]>;
getProduct(id: string): Promise<Product | undefined>;
getProductBySku(sku: string): Promise<Product | undefined>;
createProduct(product: InsertProduct): Promise<Product>;
updateProduct(id: string, product: Partial<InsertProduct>): Promise<Product | undefined>;
deleteProduct(id: string): Promise<boolean>;
searchProducts(query: string): Promise<Product[]>;
getLowStockProducts(): Promise<Product[]>;
getOutOfStockProducts(): Promise<Product[]>;
// Stock movements
getStockMovements(productId?: string): Promise<StockMovement[]>;
createStockMovement(movement: InsertStockMovement): Promise<StockMovement>;
// Documents
getDocuments(): Promise<Document[]>;
getDocument(id: string): Promise<Document | undefined>;
createDocument(document: InsertDocument): Promise<Document>;
updateDocument(id: string, document: Partial<InsertDocument>): Promise<Document | undefined>;
deleteDocument(id: string): Promise<boolean>;
// Orders
getOrders(): Promise<Order[]>;
getOrder(id: string): Promise<Order | undefined>;
createOrder(order: InsertOrder): Promise<Order>;
updateOrder(id: string, order: Partial<InsertOrder>): Promise<Order | undefined>;
// Notifications
getNotifications(): Promise<Notification[]>;
createNotification(notification: InsertNotification): Promise<Notification>;
markNotificationAsRead(id: string): Promise<boolean>;
getUnreadNotificationCount(): Promise<number>;
}
export class MemStorage implements IStorage {
private products: Map<string, Product>;
private stockMovements: Map<string, StockMovement>;
private documents: Map<string, Document>;
private orders: Map<string, Order>;
private notifications: Map<string, Notification>;
constructor() {
this.products = new Map();
this.stockMovements = new Map();
this.documents = new Map();
this.orders = new Map();
this.notifications = new Map();
// Initialize with sample data
this.initializeSampleData();
}
private initializeSampleData() {
const sampleProducts: Product[] = [
{
id: "1",
sku: "SH-001",
name: "Safety Helmets - White",
description: "High-quality safety helmets for construction work",
currentStock: 125,
minThreshold: 20,
unit: "units",
price: "29.99",
createdAt: new Date(),
updatedAt: new Date(),
},
{
id: "2",
sku: "WG-003",
name: "Work Gloves - Medium",
description: "Durable work gloves for general construction",
currentStock: 8,
minThreshold: 15,
unit: "pairs",
price: "12.50",
createdAt: new Date(),
updatedAt: new Date(),
},
{
id: "3",
sku: "HV-005",
name: "Hi-Vis Vests - Large",
description: "High-visibility safety vests",
currentStock: 0,
minThreshold: 10,
unit: "units",
price: "15.75",
createdAt: new Date(),
updatedAt: new Date(),
},
];
sampleProducts.forEach(product => {
this.products.set(product.id, product);
});
// Create notifications for low/out of stock items
const lowStockNotification: Notification = {
id: "notif-1",
type: "low_stock",
title: "Low Stock Alert",
message: "Work Gloves - Medium is below minimum threshold",
isRead: false,
relatedId: "2",
createdAt: new Date(),
};
const outOfStockNotification: Notification = {
id: "notif-2",
type: "out_of_stock",
title: "Out of Stock Alert",
message: "Hi-Vis Vests - Large is out of stock",
isRead: false,
relatedId: "3",
createdAt: new Date(),
};
this.notifications.set("notif-1", lowStockNotification);
this.notifications.set("notif-2", outOfStockNotification);
}
// Products
async getProducts(): Promise<Product[]> {
return Array.from(this.products.values());
}
async getProduct(id: string): Promise<Product | undefined> {
return this.products.get(id);
}
async getProductBySku(sku: string): Promise<Product | undefined> {
return Array.from(this.products.values()).find(product => product.sku === sku);
}
async createProduct(insertProduct: InsertProduct): Promise<Product> {
const id = randomUUID();
const product: Product = {
...insertProduct,
id,
description: insertProduct.description ?? null,
createdAt: new Date(),
updatedAt: new Date(),
};
this.products.set(id, product);
return product;
}
async updateProduct(id: string, updates: Partial<InsertProduct>): Promise<Product | undefined> {
const product = this.products.get(id);
if (!product) return undefined;
const updatedProduct: Product = {
...product,
...updates,
updatedAt: new Date(),
};
this.products.set(id, updatedProduct);
return updatedProduct;
}
async deleteProduct(id: string): Promise<boolean> {
return this.products.delete(id);
}
async searchProducts(query: string): Promise<Product[]> {
const products = Array.from(this.products.values());
const lowercaseQuery = query.toLowerCase();
return products.filter(product =>
product.name.toLowerCase().includes(lowercaseQuery) ||
product.sku.toLowerCase().includes(lowercaseQuery) ||
product.description?.toLowerCase().includes(lowercaseQuery)
);
}
async getLowStockProducts(): Promise<Product[]> {
return Array.from(this.products.values()).filter(
product => product.currentStock > 0 && product.currentStock <= product.minThreshold
);
}
async getOutOfStockProducts(): Promise<Product[]> {
return Array.from(this.products.values()).filter(
product => product.currentStock === 0
);
}
// Stock movements
async getStockMovements(productId?: string): Promise<StockMovement[]> {
const movements = Array.from(this.stockMovements.values());
if (productId) {
return movements.filter(movement => movement.productId === productId);
}
return movements;
}
async createStockMovement(insertMovement: InsertStockMovement): Promise<StockMovement> {
const id = randomUUID();
const movement: StockMovement = {
...insertMovement,
id,
reason: insertMovement.reason ?? null,
createdAt: new Date(),
};
this.stockMovements.set(id, movement);
// Update product stock
const product = this.products.get(insertMovement.productId);
if (product) {
let newStock = product.currentStock;
if (insertMovement.type === 'in') {
newStock += insertMovement.quantity;
} else if (insertMovement.type === 'out') {
newStock -= insertMovement.quantity;
} else if (insertMovement.type === 'adjustment') {
newStock = insertMovement.quantity;
}
await this.updateProduct(insertMovement.productId, { currentStock: Math.max(0, newStock) });
}
return movement;
}
// Documents
async getDocuments(): Promise<Document[]> {
return Array.from(this.documents.values());
}
async getDocument(id: string): Promise<Document | undefined> {
return this.documents.get(id);
}
async createDocument(insertDocument: InsertDocument): Promise<Document> {
const id = randomUUID();
const document: Document = {
...insertDocument,
id,
content: insertDocument.content ?? {},
status: insertDocument.status ?? "draft",
createdAt: new Date(),
updatedAt: new Date(),
};
this.documents.set(id, document);
return document;
}
async updateDocument(id: string, updates: Partial<InsertDocument>): Promise<Document | undefined> {
const document = this.documents.get(id);
if (!document) return undefined;
const updatedDocument: Document = {
...document,
...updates,
updatedAt: new Date(),
};
this.documents.set(id, updatedDocument);
return updatedDocument;
}
async deleteDocument(id: string): Promise<boolean> {
return this.documents.delete(id);
}
// Orders
async getOrders(): Promise<Order[]> {
return Array.from(this.orders.values());
}
async getOrder(id: string): Promise<Order | undefined> {
return this.orders.get(id);
}
async createOrder(insertOrder: InsertOrder): Promise<Order> {
const id = randomUUID();
const order: Order = {
...insertOrder,
id,
status: insertOrder.status ?? "pending",
createdAt: new Date(),
updatedAt: new Date(),
};
this.orders.set(id, order);
return order;
}
async updateOrder(id: string, updates: Partial<InsertOrder>): Promise<Order | undefined> {
const order = this.orders.get(id);
if (!order) return undefined;
const updatedOrder: Order = {
...order,
...updates,
updatedAt: new Date(),
};
this.orders.set(id, updatedOrder);
return updatedOrder;
}
// Notifications
async getNotifications(): Promise<Notification[]> {
return Array.from(this.notifications.values()).sort(
(a, b) => (b.createdAt?.getTime() || 0) - (a.createdAt?.getTime() || 0)
);
}
async createNotification(insertNotification: InsertNotification): Promise<Notification> {
const id = randomUUID();
const notification: Notification = {
...insertNotification,
id,
isRead: insertNotification.isRead ?? false,
relatedId: insertNotification.relatedId ?? null,
createdAt: new Date(),
};
this.notifications.set(id, notification);
return notification;
}
async markNotificationAsRead(id: string): Promise<boolean> {
const notification = this.notifications.get(id);
if (!notification) return false;
notification.isRead = true;
this.notifications.set(id, notification);
return true;
}
async getUnreadNotificationCount(): Promise<number> {
return Array.from(this.notifications.values()).filter(n => !n.isRead).length;
}
}
export const storage = new MemStorage();