fix karung view data and sync only sync with the current date
This commit is contained in:
1 parent
b3556c6ef4
commit
5ae477a99d
8 files changed
+396
-32
No files matched your search
@@ -8,6 +8,7 @@ from urllib.parse import urljoin
|
||||
import httpx
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.utils import timezone
|
||||
|
||||
from apps.farms.models import Cycle
|
||||
from apps.operations.models import FeedSacks
|
||||
@@ -51,6 +52,117 @@ def _normalize_source(value: str | None) -> str:
|
||||
return (value or "").strip().casefold()
|
||||
|
||||
|
||||
def _parse_history_date(raw: Any) -> date | None:
|
||||
if raw is None:
|
||||
return None
|
||||
try:
|
||||
return date.fromisoformat(str(raw)[:10])
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def daily_totals_from_combined_history(
|
||||
combined: dict[str, Any],
|
||||
*,
|
||||
kandang_name: str,
|
||||
) -> dict[date, dict[str, int]]:
|
||||
"""Group /api/combined history into per-date in/out/use for one kandang."""
|
||||
in_source = _normalize_source(source_for_kandang(kandang_name, kind="In"))
|
||||
out_source = _normalize_source(source_for_kandang(kandang_name, kind="Out"))
|
||||
use_source = _normalize_source(source_for_kandang(kandang_name, kind="Use"))
|
||||
|
||||
by_date: dict[date, dict[str, int]] = {}
|
||||
|
||||
def ensure(day: date) -> dict[str, int]:
|
||||
return by_date.setdefault(
|
||||
day, {"in_today": 0, "out_today": 0, "feed_use_today": 0}
|
||||
)
|
||||
|
||||
masuk_history = (combined.get("masuk") or {}).get("history") or []
|
||||
for row in masuk_history:
|
||||
day = _parse_history_date(row.get("date"))
|
||||
if day is None:
|
||||
continue
|
||||
source = _normalize_source(row.get("source"))
|
||||
value = int(row.get("counter_value") or row.get("karung") or 0)
|
||||
if source == in_source:
|
||||
ensure(day)["in_today"] = value
|
||||
elif source == out_source:
|
||||
ensure(day)["out_today"] = value
|
||||
|
||||
tuang_history = (combined.get("tuang") or {}).get("history") or []
|
||||
for row in tuang_history:
|
||||
day = _parse_history_date(row.get("date"))
|
||||
if day is None:
|
||||
continue
|
||||
source = _normalize_source(row.get("source"))
|
||||
value = int(row.get("counter_value") or row.get("karung") or 0)
|
||||
if source == use_source:
|
||||
ensure(day)["feed_use_today"] = value
|
||||
|
||||
return by_date
|
||||
|
||||
|
||||
def cycle_history_window(cycle: Cycle, *, today: date | None = None) -> tuple[date, date]:
|
||||
"""Inclusive date window for history upserts."""
|
||||
if today is None:
|
||||
today = timezone.localdate()
|
||||
end = min(today, cycle.end_date)
|
||||
return cycle.start_date, end
|
||||
|
||||
|
||||
def backfill_karung_from_combined(
|
||||
cycle: Cycle,
|
||||
combined: dict[str, Any] | None = None,
|
||||
) -> list[date]:
|
||||
"""Upsert FeedSacks for cycle dates present in combined history. Returns upserted dates."""
|
||||
if combined is None:
|
||||
combined = KarungWebClient().fetch_combined()
|
||||
|
||||
kandang_name = cycle.kandang.kandang_name
|
||||
by_date = daily_totals_from_combined_history(combined, kandang_name=kandang_name)
|
||||
start, end = cycle_history_window(cycle)
|
||||
upserted: list[date] = []
|
||||
|
||||
for day in sorted(by_date):
|
||||
if day < start or day > end:
|
||||
continue
|
||||
totals = by_date[day]
|
||||
FeedSacks.objects.update_or_create(
|
||||
cycle=cycle,
|
||||
date=day,
|
||||
defaults={
|
||||
"in_today": totals["in_today"],
|
||||
"out_today": totals["out_today"],
|
||||
"feed_use_today": totals["feed_use_today"],
|
||||
},
|
||||
)
|
||||
upserted.append(day)
|
||||
return upserted
|
||||
|
||||
|
||||
def recompute_feed_sack_totals(cycle: Cycle) -> None:
|
||||
"""Recompute running in/out/use totals for all FeedSacks of a cycle in date order."""
|
||||
running_in = 0
|
||||
running_out = 0
|
||||
running_use = 0
|
||||
rows = list(FeedSacks.objects.filter(cycle=cycle).order_by("date", "pk"))
|
||||
for row in rows:
|
||||
running_in += row.in_today or 0
|
||||
running_out += row.out_today or 0
|
||||
running_use += row.feed_use_today or 0
|
||||
changed = (
|
||||
row.in_total != running_in
|
||||
or row.out_total != running_out
|
||||
or row.feed_use_total != running_use
|
||||
)
|
||||
if changed:
|
||||
row.in_total = running_in
|
||||
row.out_total = running_out
|
||||
row.feed_use_total = running_use
|
||||
row.save(update_fields=["in_total", "out_total", "feed_use_total", "updated_at"])
|
||||
|
||||
|
||||
class KarungWebClient:
|
||||
"""Outbound client for karung-web-admin — base URL from settings only."""
|
||||
|
||||
@@ -155,7 +267,7 @@ def request_karung(
|
||||
saldo_awal = int(remote_cycle.get("saldo_awal") or 0)
|
||||
|
||||
snapshot_raw = block.get("date")
|
||||
snapshot_date = date.fromisoformat(str(snapshot_raw)) if snapshot_raw else date.today()
|
||||
snapshot_date = date.fromisoformat(str(snapshot_raw)) if snapshot_raw else timezone.localdate()
|
||||
|
||||
prior = (
|
||||
FeedSacks.objects.filter(cycle=cycle)
|
||||
@@ -203,3 +315,20 @@ def request_karung(
|
||||
"remote_cycle": remote_cycle,
|
||||
}
|
||||
return feed_sack, summary
|
||||
|
||||
|
||||
def sync_karung_for_cycle(
|
||||
cycle: Cycle,
|
||||
*,
|
||||
section: str = "today",
|
||||
) -> tuple[FeedSacks, dict[str, Any]]:
|
||||
"""Sync today from sections, backfill cycle history from /api/combined, recompute totals."""
|
||||
feed_sack, summary = request_karung(cycle, section=section)
|
||||
history_dates = backfill_karung_from_combined(cycle)
|
||||
recompute_feed_sack_totals(cycle)
|
||||
feed_sack.refresh_from_db()
|
||||
summary = {
|
||||
**summary,
|
||||
"history_dates": [d.isoformat() for d in history_dates],
|
||||
}
|
||||
return feed_sack, summary
|
||||
Reference in new issue
Block a user