From 3fe6b05258c950c2ae2f2aa5463c0b3956bdf29f Mon Sep 17 00:00:00 2001 From: Alberto-Audrix Date: Fri, 2 Oct 2026 10:47:00 +0700 Subject: [PATCH] fix day 1 target weight bug and chicken counting row not showed before publish cutoff --- components/counting/DataManagementPage.tsx | 6 ++++-- .../__tests__/DataManagementPage.test.tsx | 2 +- utils/__tests__/weight.test.ts | 17 +++++++++++++---- utils/countingAccuracyWarning.ts | 7 ++++--- utils/weight.ts | 7 ++++++- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/components/counting/DataManagementPage.tsx b/components/counting/DataManagementPage.tsx index a5ebaab..91518b3 100644 --- a/components/counting/DataManagementPage.tsx +++ b/components/counting/DataManagementPage.tsx @@ -6,7 +6,6 @@ import { Banner, EmptyFarm, PageHeader, Spinner } from '../ui/Feedback.tsx'; import { addDaysIso, cycleDayForDate, - cycleLastDayIndex, formatDateId, formatDateRange, formatNumber, @@ -116,8 +115,11 @@ const DataManagementPage: React.FC<{ onSettings: () => void }> = ({ onSettings } const kpiByDate = new Map(kpis.map((k) => [k.date, k])); const lastCycleDay = Math.max(0, (selectedCycle.total_days || 1) - 1); - const endDay = cycleLastDayIndex(selectedCycle); const calendarDay = cycleDayForDate(selectedCycle.start_date, todayIso()); + // Closed cycles stop at end_date; active / open cycles build daily rows through calendar today. + const endDay = selectedCycle.end_date + ? cycleDayForDate(selectedCycle.start_date, selectedCycle.end_date) + : calendarDay; const maxDay = Math.min(calendarDay, lastCycleDay, endDay); const today = todayIso(); diff --git a/components/counting/__tests__/DataManagementPage.test.tsx b/components/counting/__tests__/DataManagementPage.test.tsx index e387877..2368f31 100644 --- a/components/counting/__tests__/DataManagementPage.test.tsx +++ b/components/counting/__tests__/DataManagementPage.test.tsx @@ -55,7 +55,7 @@ vi.mock('../../../context/FarmContext.tsx', () => ({ current_day: 1, visible_through_date: '2026-08-10', start_date: '2026-08-10', - end_date: '2026-09-13', + end_date: null, chick_in_weight: 45, doc_in_count: 20000, doc_in_weight: 45, diff --git a/utils/__tests__/weight.test.ts b/utils/__tests__/weight.test.ts index db2f677..1b8c93c 100644 --- a/utils/__tests__/weight.test.ts +++ b/utils/__tests__/weight.test.ts @@ -25,8 +25,9 @@ describe('getTargetWeightForAge', () => { expect(getTargetWeightForAge(7, 60)).toBe(row.values[6]); }); - it('returns null for ages outside 1..35', () => { - expect(getTargetWeightForAge(0, 42)).toBeNull(); + it('returns docWeight for age 0 and null for ages outside 0..35', () => { + expect(getTargetWeightForAge(0, 42)).toBe(42); + expect(getTargetWeightForAge(-1, 42)).toBeNull(); expect(getTargetWeightForAge(36, 42)).toBeNull(); }); }); @@ -37,7 +38,15 @@ describe('getTargetGainForAge', () => { expect(getTargetGainForAge(2, 40)).toBe(row.values[1]! - row.values[0]!); }); - it('returns null for age 1', () => { - expect(getTargetGainForAge(1, 40)).toBeNull(); + it('calculates target gain for age 1 relative to docWeight', () => { + const row = rowForDoc(40); + expect(getTargetGainForAge(1, 40)).toBe(row.values[0]! - 40); + }); + + it('returns null for ages outside 1..35 or invalid docWeight', () => { + expect(getTargetGainForAge(0, 40)).toBeNull(); + expect(getTargetGainForAge(36, 40)).toBeNull(); + expect(getTargetGainForAge(1, 0)).toBeNull(); + expect(getTargetGainForAge(1, -5)).toBeNull(); }); }); diff --git a/utils/countingAccuracyWarning.ts b/utils/countingAccuracyWarning.ts index 0a89b06..86b6980 100644 --- a/utils/countingAccuracyWarning.ts +++ b/utils/countingAccuracyWarning.ts @@ -1,5 +1,5 @@ import type { ChickenCounting, Cycle, KPI, ManualInput } from '../types/api.ts'; -import { addDaysIso, cycleDayForDate, cycleLastDayIndex } from './format.ts'; +import { addDaysIso, cycleDayForDate, todayIso } from './format.ts'; import { stockAkhirFromKpi } from './kpiStock.ts'; export const COUNTING_ACCURACY_WARNING_THRESHOLD = 95; @@ -39,8 +39,9 @@ function stockAkhirByDate( const manualByDate = new Map(manualInputs.map((m) => [m.date, m])); const lastCycleDay = Math.max(0, (cycle.total_days || 1) - 1); - const endDay = cycleLastDayIndex(cycle); - const maxDay = Math.min(lastCycleDay, endDay); + const calendarDay = cycleDayForDate(cycle.start_date, todayIso()); + const endDay = cycle.end_date ? cycleDayForDate(cycle.start_date, cycle.end_date) : calendarDay; + const maxDay = Math.min(calendarDay, lastCycleDay, endDay); const result = new Map(); let previousStockAkhir = 0; diff --git a/utils/weight.ts b/utils/weight.ts index 9bf518d..f450a47 100644 --- a/utils/weight.ts +++ b/utils/weight.ts @@ -70,7 +70,12 @@ export function getTargetWeightForAge(age: number, docWeight: number): number | /** Target daily weight gain (grams/day) for a given age from the standard. */ export function getTargetGainForAge(age: number, docWeight: number): number | null { const values = pickStandardValues(docWeight); - if (age < 2 || age > values.length) return null; + if (age < 1 || age > values.length) return null; + if (age === 1) { + const current = values[0]; + if (current == null || docWeight <= 0) return null; + return current - docWeight; + } const current = values[age - 1]; const previous = values[age - 2]; if (current == null || previous == null) return null;