129 lines
4.2 KiB
TypeScript
129 lines
4.2 KiB
TypeScript
import { db } from '@/src/db/db_index'
|
|
import { productInfo, productAvailabilitySchedules } from '@/src/db/schema'
|
|
import { eq, inArray } from 'drizzle-orm';
|
|
import { initializeAllStores } from '@/src/stores/store-initializer';
|
|
import dayjs from 'dayjs';
|
|
|
|
/**
|
|
* Get all products that should be in stock or out of stock based on current schedules
|
|
* Only processes products that are actually involved in availability schedules
|
|
* Automatically updates products that need to change their availability status
|
|
* @returns Promise<{ inStock: number[], outOfStock: number[], changed: number[] }>
|
|
*/
|
|
export async function verifyProductsAvailabilityBySchedule(reInitialize:boolean = false): Promise<{
|
|
inStock: number[];
|
|
outOfStock: number[];
|
|
changed: number[];
|
|
}> {
|
|
// Get all schedules
|
|
const allSchedules = await db.query.productAvailabilitySchedules.findMany();
|
|
|
|
// Extract all unique product IDs from all schedules
|
|
const allScheduledProductIds = new Set<number>();
|
|
for (const schedule of allSchedules) {
|
|
for (const productId of schedule.productIds) {
|
|
allScheduledProductIds.add(productId);
|
|
}
|
|
}
|
|
|
|
// If no products are in any schedule, return empty arrays
|
|
if (allScheduledProductIds.size === 0) {
|
|
return { inStock: [], outOfStock: [], changed: [] };
|
|
}
|
|
|
|
// Get current time
|
|
const currentTime = dayjs().format('HH:mm');
|
|
|
|
const computedInStock: number[] = [];
|
|
const computedOutOfStock: number[] = [];
|
|
|
|
// Process each product that is involved in schedules
|
|
for (const productId of allScheduledProductIds) {
|
|
// Find applicable schedules for this product
|
|
const applicableSchedules = allSchedules.filter(schedule => {
|
|
return schedule.productIds.includes(productId);
|
|
});
|
|
|
|
// Filter active schedules (time <= current time)
|
|
const activeSchedules = applicableSchedules.filter(schedule =>
|
|
schedule.time <= currentTime
|
|
);
|
|
|
|
if (activeSchedules.length === 0) {
|
|
// No active schedule applies - skip this product
|
|
// (we only care about products with active schedule rules)
|
|
continue;
|
|
}
|
|
|
|
// Get most recent schedule
|
|
const mostRecentSchedule = activeSchedules.sort((a, b) => {
|
|
if (a.time !== b.time) {
|
|
return b.time.localeCompare(a.time);
|
|
}
|
|
return b.id - a.id;
|
|
})[0];
|
|
|
|
// Categorize based on schedule action
|
|
if (mostRecentSchedule.action === 'in') {
|
|
computedInStock.push(productId);
|
|
} else {
|
|
computedOutOfStock.push(productId);
|
|
}
|
|
}
|
|
|
|
// Query products to check current availability status
|
|
const allProductIds = [...computedInStock, ...computedOutOfStock];
|
|
|
|
if (allProductIds.length === 0) {
|
|
return { inStock: [], outOfStock: [], changed: [] };
|
|
}
|
|
|
|
const products = await db.query.productInfo.findMany({
|
|
where: inArray(productInfo.id, allProductIds),
|
|
});
|
|
|
|
// Find products that need to change
|
|
const toMarkInStock: number[] = [];
|
|
const toMarkOutOfStock: number[] = [];
|
|
const changed: number[] = [];
|
|
|
|
for (const product of products) {
|
|
const shouldBeInStock = computedInStock.includes(product.id);
|
|
const currentlyOutOfStock = product.isOutOfStock;
|
|
|
|
if (shouldBeInStock && currentlyOutOfStock) {
|
|
// Should be in stock but currently out of stock - needs change
|
|
toMarkInStock.push(product.id);
|
|
changed.push(product.id);
|
|
} else if (!shouldBeInStock && !currentlyOutOfStock) {
|
|
// Should be out of stock but currently in stock - needs change
|
|
toMarkOutOfStock.push(product.id);
|
|
changed.push(product.id);
|
|
}
|
|
}
|
|
|
|
// Batch update products in a single query
|
|
if (toMarkInStock.length > 0) {
|
|
await db.update(productInfo)
|
|
.set({ isOutOfStock: false })
|
|
.where(inArray(productInfo.id, toMarkInStock));
|
|
}
|
|
|
|
if (toMarkOutOfStock.length > 0) {
|
|
await db.update(productInfo)
|
|
.set({ isOutOfStock: true })
|
|
.where(inArray(productInfo.id, toMarkOutOfStock));
|
|
}
|
|
|
|
// Reinitialize stores if any products changed
|
|
if (changed.length > 0 && reInitialize) {
|
|
console.log(`Reinitializing stores after availability changes for ${changed.length} products`);
|
|
await initializeAllStores();
|
|
}
|
|
|
|
return {
|
|
inStock: computedInStock,
|
|
outOfStock: computedOutOfStock,
|
|
changed
|
|
};
|
|
}
|