Files
butcem/src/models/shopping-list.ts
T
suphicakir 8ab2244755 feat(shopping): alışveriş listeleri, stok eşiği önerileri ve akıllı mağaza önerisi motoru
- shoppingLists koleksiyonu (ürün tipi / marka / serbest metin kalemleri), migration 015
- planShopping saf fonksiyonu: paket yuvarlama, zahmet ve hacimli cezası, teslimat, yemek kartı önceliği, ek mağaza eşiği
- eşik önerileri onay/red (red stok yenilenene kadar), ürün tipine hacimli işareti
- fiyat servisinde ortak loadTypeOffers; seed listeleri ve testler

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 23:28:54 +03:00

62 lines
2.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { model, models, Schema, type InferSchemaType, type Model } from "mongoose";
import {
SHOPPING_ITEM_KINDS,
SHOPPING_ITEM_SOURCES,
SHOPPING_LIST_STATUSES,
} from "@/shared/shopping";
/**
* Alışveriş kalemi (Bölüm 6.12): ürün tipi (genel), belirli ürün (marka/paket) ya da serbest metin.
* Miktar binde bir: ürün tipinde tipin biriminde, üründe paket adedi, serbest metinde `unit` ile.
* `checked`: alışveriş modunda sepete alındı.
*/
const shoppingItemSchema = new Schema(
{
kind: { type: String, enum: SHOPPING_ITEM_KINDS, required: true },
productTypeId: { type: Schema.Types.ObjectId, default: null },
productId: { type: Schema.Types.ObjectId, default: null },
text: { type: String, default: "", trim: true, maxlength: 120 },
/** Boşsa "1 paket" kabul edilir. */
quantity: { type: Number, default: null, min: 0 },
/** Serbest metin kaleminin birimi. */
unit: { type: String, default: "", trim: true, maxlength: 20 },
note: { type: String, default: "", trim: true, maxlength: 200 },
source: { type: String, enum: SHOPPING_ITEM_SOURCES, default: "manual" },
checked: { type: Boolean, default: false },
checkedBy: { type: Schema.Types.ObjectId, default: null },
checkedAt: { type: Date, default: null },
addedBy: { type: Schema.Types.ObjectId, required: true },
addedAt: { type: Date, default: () => new Date() },
},
{ _id: true },
);
/** Alışveriş listesi; hane içinde ortak. Birden çok aktif liste olabilir. Silme: soft delete. */
const shoppingListSchema = new Schema(
{
householdId: { type: Schema.Types.ObjectId, required: true },
name: { type: String, required: true, trim: true, maxlength: 80 },
status: { type: String, enum: SHOPPING_LIST_STATUSES, default: "active" },
note: { type: String, default: "", trim: true, maxlength: 300 },
items: { type: [shoppingItemSchema], default: [] },
completedAt: { type: Date, default: null },
deletedAt: { type: Date, default: null },
seedRef: { type: String, default: null },
createdBy: { type: Schema.Types.ObjectId, required: true },
updatedBy: { type: Schema.Types.ObjectId, required: true },
},
{ timestamps: true, collection: "shoppingLists" },
);
shoppingListSchema.index({ householdId: 1, deletedAt: 1, status: 1, updatedAt: -1 });
shoppingListSchema.index(
{ householdId: 1, seedRef: 1 },
{ unique: true, partialFilterExpression: { seedRef: { $type: "string" } } },
);
export type ShoppingList = InferSchemaType<typeof shoppingListSchema>;
export const ShoppingListModel: Model<ShoppingList> =
(models.ShoppingList as Model<ShoppingList> | undefined) ??
model<ShoppingList>("ShoppingList", shoppingListSchema);