Files
butcem/src/models/account.ts
T

73 lines
3.2 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 { ACCOUNT_TYPES, DUE_RULE_KINDS, MEAL_CARD_PROVIDERS } from "@/shared/accounts";
import { ICON_KEYS, SWATCHES } from "@/shared/appearance";
/**
* Hesap (Bölüm 6.1). Tutarlar kuruş. Bakiye işareti: varlık pozitif, kart borcu negatif.
* Güncel bakiyenin tek doğruluk kaynağı işlemlerdir (Faz 6b); `balanceCacheMinor` yalnızca önbellek.
*/
const overdraftSchema = new Schema(
{
enabled: { type: Boolean, default: false },
limitMinor: { type: Number, min: 0, default: 0 },
/** Aylık faiz oranı, baz puan (4,25% → 425). */
monthlyRateBp: { type: Number, min: 0, max: 10_000, default: null },
statementDay: { type: Number, min: 1, max: 31, default: null },
},
{ _id: false },
);
const creditCardSchema = new Schema(
{
limitMinor: { type: Number, min: 0, default: 0 },
/** Hesap kesim günü; ayda yoksa (31) ayın son günü kullanılır (Faz 7). */
statementDay: { type: Number, min: 1, max: 31, default: 1 },
dueRule: {
kind: { type: String, enum: DUE_RULE_KINDS, default: "daysAfter" },
value: { type: Number, min: 1, max: 31, default: 10 },
},
/**
* Asgari ödeme oranı, baz puan (2000 = %20). null → varsayılan kural: limit 50.000 TL altı %20,
* üstü %40 (Faz 7 kararı).
*/
minimumPaymentRateBp: { type: Number, min: 0, max: 10_000, default: null },
/** Kart borcunun ödeneceği varsayılan hesap. */
paymentAccountId: { type: Schema.Types.ObjectId, default: null },
},
{ _id: false },
);
const accountSchema = new Schema(
{
householdId: { type: Schema.Types.ObjectId, required: true },
name: { type: String, required: true, trim: true, maxlength: 80 },
type: { type: String, enum: ACCOUNT_TYPES, required: true },
institution: { type: String, trim: true, maxlength: 80, default: "" },
mealCardProvider: { type: String, enum: [...MEAL_CARD_PROVIDERS, null], default: null },
/** İleride döviz hesabı için; şimdilik yalnızca TRY. */
currency: { type: String, enum: ["TRY"], default: "TRY" },
openingBalanceMinor: { type: Number, required: true, default: 0 },
openingDate: { type: Date, required: true },
color: { type: String, enum: SWATCHES, default: "blue" },
icon: { type: String, enum: ICON_KEYS, default: "wallet" },
order: { type: Number, default: 0 },
archivedAt: { type: Date, default: null },
/** Hesabın sahibi kişi (hane üyesi). "Yalnızca ben" hesaplarında bakiyeyi yalnızca o görür. */
ownerUserId: { type: Schema.Types.ObjectId, default: null },
isPrivate: { type: Boolean, default: false },
overdraft: { type: overdraftSchema, default: null },
creditCard: { type: creditCardSchema, default: null },
balanceCacheMinor: { type: Number, default: null },
createdBy: { type: Schema.Types.ObjectId, required: true },
updatedBy: { type: Schema.Types.ObjectId, required: true },
},
{ timestamps: true, collection: "accounts" },
);
accountSchema.index({ householdId: 1, archivedAt: 1, order: 1 });
export type Account = InferSchemaType<typeof accountSchema>;
export const AccountModel: Model<Account> =
(models.Account as Model<Account> | undefined) ?? model<Account>("Account", accountSchema);