feat(budget): gelir planı ve günlük plan
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { dailyPlan, distribute, patternWeights } from "./daily-plan";
|
||||
|
||||
describe("dağıtım", () => {
|
||||
it("toplam korunur, kalan kuruşlar en büyük kesirlere", () => {
|
||||
expect(distribute(100, [1, 1, 1])).toEqual([34, 33, 33]);
|
||||
expect(distribute(10, [1, 0, 3])).toEqual([3, 0, 7]);
|
||||
expect(distribute(5, [0, 0])).toEqual([3, 2]);
|
||||
expect(distribute(0, [1, 2])).toEqual([0, 0]);
|
||||
expect(distribute(7, [])).toEqual([]);
|
||||
});
|
||||
|
||||
it("önceki ayın örüntüsü gün sayısına uyarlanır", () => {
|
||||
expect(patternWeights([5, 0, 2], 4)).toEqual([5, 0, 2, 2]);
|
||||
expect(patternWeights([5, 0, 2, 1], 2)).toEqual([5, 0]);
|
||||
expect(patternWeights([], 2)).toEqual([1, 1]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("günlük plan", () => {
|
||||
// Aralık: 31 gün. Bütçe 31.000 + kira 10.000 (1'inde) + fatura 3.100 (15'inde).
|
||||
const base = {
|
||||
from: "2026-12-01",
|
||||
to: "2026-12-31",
|
||||
budgetMinor: 44_100_00,
|
||||
fixedByDay: new Map([
|
||||
["2026-12-01", 10_000_00],
|
||||
["2026-12-15", 3_100_00],
|
||||
]),
|
||||
};
|
||||
|
||||
it("sabit giderler kendi gününe, değişken bütçe eşit; kümülatif ve yüzde", () => {
|
||||
const p = dailyPlan({
|
||||
...base,
|
||||
today: "2026-12-13",
|
||||
actualByDay: new Map([
|
||||
["2026-12-01", 10_500_00],
|
||||
["2026-12-05", 9_000_00],
|
||||
["2026-12-13", 2_000_00],
|
||||
]),
|
||||
});
|
||||
expect(p.variableMinor).toBe(31_000_00);
|
||||
expect(p.days[0]!.plannedMinor).toBe(11_000_00);
|
||||
expect(p.days[1]!.plannedMinor).toBe(1_000_00);
|
||||
expect(p.days[14]!.plannedMinor).toBe(4_100_00);
|
||||
expect(p.days.at(-1)!.cumPlannedMinor).toBe(44_100_00);
|
||||
expect(p.todayIndex).toBe(12);
|
||||
// 13/31 gün → %42; 21.500 / 44.100 → %49
|
||||
expect(p.monthPct).toBe(42);
|
||||
expect(p.spentPct).toBe(49);
|
||||
expect(p.plannedToDateMinor).toBe(23_000_00);
|
||||
expect(p.actualToDateMinor).toBe(21_500_00);
|
||||
// Bugün: 1.000 + (12 günlük plan 22.000 − harcanan 19.500 = 2.500)
|
||||
expect(p.todayAllowanceMinor).toBe(3_500_00);
|
||||
});
|
||||
|
||||
it("sabit giderler bütçeyi aşarsa değişken 0; dönem dışı bugün; ağırlıklı dağıtım", () => {
|
||||
const over = dailyPlan({
|
||||
...base,
|
||||
budgetMinor: 5_000_00,
|
||||
today: "2027-01-05",
|
||||
actualByDay: new Map(),
|
||||
});
|
||||
expect(over.variableMinor).toBe(0);
|
||||
expect(over.todayIndex).toBe(-1);
|
||||
expect(over.monthPct).toBe(100);
|
||||
const weights = Array.from({ length: 31 }, (_, i) => (i % 7 === 5 ? 3 : 1));
|
||||
const w = dailyPlan({ ...base, today: "2026-11-20", actualByDay: new Map(), weights });
|
||||
expect(w.monthPct).toBe(0);
|
||||
expect(w.days[5]!.plannedMinor).toBeGreaterThan(w.days[6]!.plannedMinor);
|
||||
expect(w.days.at(-1)!.cumPlannedMinor).toBe(44_100_00);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user