first commit
This commit is contained in:
commit
367533c02b
171 files changed
+101175
No files matched your search
@@ -0,0 +1,106 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from typing import Any
|
||||
from urllib.parse import urljoin
|
||||
|
||||
import httpx
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from apps.farms.models import Cycle
|
||||
from apps.operations.models import FeedSacks
|
||||
|
||||
|
||||
class KarungWebError(Exception):
|
||||
def __init__(self, message: str, status_code: int | None = None):
|
||||
super().__init__(message)
|
||||
self.status_code = status_code
|
||||
|
||||
|
||||
class KarungWebClient:
|
||||
"""Outbound client for karung-web-admin — base URL from settings only."""
|
||||
|
||||
PATH = "/api/v1/cycles/active/sections"
|
||||
|
||||
def __init__(self, base_url: str | None = None, timeout: float | None = None):
|
||||
self.base_url = (base_url or settings.KARUNG_WEB_ADMIN_BASE_URL).rstrip("/")
|
||||
self.timeout = timeout or settings.KARUNG_WEB_ADMIN_TIMEOUT_SECONDS
|
||||
|
||||
def fetch_active_sections(self) -> dict[str, Any]:
|
||||
url = urljoin(self.base_url + "/", self.PATH.lstrip("/"))
|
||||
try:
|
||||
with httpx.Client(timeout=self.timeout) as client:
|
||||
response = client.get(url)
|
||||
except httpx.HTTPError as exc:
|
||||
raise KarungWebError(f"karung-web-admin request failed: {exc}") from exc
|
||||
if response.status_code >= 400:
|
||||
raise KarungWebError(
|
||||
f"karung-web-admin HTTP {response.status_code}: {response.text[:300]}",
|
||||
status_code=response.status_code,
|
||||
)
|
||||
payload = response.json()
|
||||
if not payload.get("success", True):
|
||||
error = payload.get("error") or {}
|
||||
raise KarungWebError(error.get("message") or "karung-web-admin returned failure")
|
||||
return payload.get("data") or payload
|
||||
|
||||
|
||||
def request_karung(
|
||||
cycle: Cycle,
|
||||
*,
|
||||
section: str = "today",
|
||||
) -> tuple[FeedSacks, dict[str, Any]]:
|
||||
if section not in {"today", "yesterday_history"}:
|
||||
raise ValidationError("section must be today or yesterday_history")
|
||||
|
||||
client = KarungWebClient()
|
||||
data = client.fetch_active_sections()
|
||||
sections = data.get("sections") or {}
|
||||
block = sections.get(section) or {}
|
||||
totals = block.get("totals") or {}
|
||||
remote_cycle = data.get("cycle") or {}
|
||||
|
||||
in_today = int(totals.get("masuk") or 0)
|
||||
out_today = int(totals.get("tuang") or 0)
|
||||
feed_use_today = out_today
|
||||
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()
|
||||
|
||||
prior = (
|
||||
FeedSacks.objects.filter(cycle=cycle)
|
||||
.exclude(date=snapshot_date)
|
||||
.order_by("-date", "-pk")
|
||||
.first()
|
||||
)
|
||||
if prior:
|
||||
in_total = prior.in_total + in_today
|
||||
out_total = prior.out_total + out_today
|
||||
feed_use_total = prior.feed_use_total + feed_use_today
|
||||
else:
|
||||
in_total = cycle.feed_initial_balance + in_today
|
||||
out_total = out_today
|
||||
feed_use_total = feed_use_today
|
||||
|
||||
feed_sack, _ = FeedSacks.objects.update_or_create(
|
||||
cycle=cycle,
|
||||
date=snapshot_date,
|
||||
defaults={
|
||||
"in_today": in_today,
|
||||
"out_today": out_today,
|
||||
"in_total": in_total,
|
||||
"out_total": out_total,
|
||||
"feed_use_today": feed_use_today,
|
||||
"feed_use_total": feed_use_total,
|
||||
},
|
||||
)
|
||||
summary = {
|
||||
"section": section,
|
||||
"snapshot_date": snapshot_date.isoformat(),
|
||||
"totals": totals,
|
||||
"saldo_awal": saldo_awal,
|
||||
"remote_cycle": remote_cycle,
|
||||
}
|
||||
return feed_sack, summary
|
||||
Reference in new issue
Block a user