import { Types } from "mongoose"; import { StockCountModel } from "@/models/stock-count"; import { StockMovementModel } from "@/models/stock-movement"; import { signedDelta, type StockMovementKind } from "@/shared/stock"; import type { Migration } from "./types"; type Move = { _id: Types.ObjectId; householdId: Types.ObjectId; productTypeId: Types.ObjectId; kind: StockMovementKind; date: string; quantity: number; initial: boolean; countId: Types.ObjectId | null; createdBy: Types.ObjectId; createdAt: Date; }; /** * Faz 11b: sayım oturumları. Faz 11a'da tek ürün sayımıyla oluşan (oturumsuz) sayım * düzeltmeleri, o ana kadarki kayıtlardan beklenen miktar hesaplanarak hane + tarih + kişi * başına bir sayım oturumuna bağlanır. Başlangıç miktarları sayım sayılmaz. */ export const migration: Migration = { name: "012-stock-counts", description: "stockCounts index'leri; oturumsuz sayım düzeltmelerini sayım oturumuna bağla", async up() { await StockCountModel.createIndexes(); const orphans = await StockMovementModel.find({ kind: "count_adjust", initial: { $ne: true }, countId: null, deletedAt: null, }).lean(); if (orphans.length === 0) return; const products = [...new Set(orphans.map((o) => String(o.productTypeId)))]; const all = await StockMovementModel.find({ productTypeId: { $in: products.map((id) => new Types.ObjectId(id)) }, deletedAt: null, }).lean(); const byProduct = new Map(); for (const m of all) { const list = byProduct.get(String(m.productTypeId)) ?? []; list.push(m); byProduct.set(String(m.productTypeId), list); } // Her düzeltme için beklenen = önceki hareketlerin toplamı (tarih, oluşturulma sırası). const expectedOf = new Map(); for (const list of byProduct.values()) { list.sort((a, b) => a.date === b.date ? a.createdAt.getTime() - b.createdAt.getTime() : a.date < b.date ? -1 : 1, ); let running = 0; for (const m of list) { expectedOf.set(String(m._id), running); running += signedDelta(m); } } const sessions = new Map(); for (const o of orphans) { const key = `${o.householdId}:${o.date}:${o.createdBy}`; sessions.set(key, [...(sessions.get(key) ?? []), o]); } for (const moves of sessions.values()) { const first = moves[0]!; const count = await StockCountModel.create({ householdId: first.householdId, date: first.date, categoryId: null, items: moves.map((m) => { const expected = expectedOf.get(String(m._id)) ?? 0; return { productTypeId: m.productTypeId, expected, actual: expected + m.quantity, wasted: 0, }; }), createdBy: first.createdBy, }); await StockMovementModel.updateMany( { _id: { $in: moves.map((m) => m._id) } }, { $set: { countId: count._id } }, ); } }, };