fix feed data pull from api using total instead of each kandang data
This commit is contained in:
1 parent
54d65724aa
commit
55ccc84386
2 files changed
+109
-7
No files matched your search
@@ -19,14 +19,32 @@ class KarungWebError(Exception):
|
||||
self.status_code = status_code
|
||||
|
||||
|
||||
def masuk_source_for_kandang(kandang_name: str) -> str:
|
||||
"""Map a kandang label like ``Kandang 1`` to the karung-web-admin source ``K1 - In``."""
|
||||
def kandang_index(kandang_name: str) -> str:
|
||||
"""Extract the numeric kandang index from labels like ``Kandang 1``."""
|
||||
match = re.search(r"(\d+)", kandang_name or "")
|
||||
if not match:
|
||||
raise ValidationError(
|
||||
f"Cannot derive IoT masuk source from kandang name: {kandang_name!r}"
|
||||
f"Cannot derive IoT kandang index from kandang name: {kandang_name!r}"
|
||||
)
|
||||
return f"K{match.group(1)} - In"
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def source_for_kandang(kandang_name: str, *, kind: str) -> str:
|
||||
"""Map a kandang label to a karung-web-admin source such as ``K1 - In``."""
|
||||
return f"K{kandang_index(kandang_name)} - {kind}"
|
||||
|
||||
|
||||
def masuk_source_for_kandang(kandang_name: str) -> str:
|
||||
"""Map a kandang label like ``Kandang 1`` to the karung-web-admin source ``K1 - In``."""
|
||||
return source_for_kandang(kandang_name, kind="In")
|
||||
|
||||
|
||||
def _karung_for_source(rows: list[dict[str, Any]] | None, expected_source: str) -> int:
|
||||
normalized = _normalize_source(expected_source)
|
||||
for row in rows or []:
|
||||
if _normalize_source(row.get("source")) == normalized:
|
||||
return int(row.get("karung") or row.get("counter_value") or 0)
|
||||
return 0
|
||||
|
||||
|
||||
def _normalize_source(value: str | None) -> str:
|
||||
@@ -126,10 +144,14 @@ def request_karung(
|
||||
block = sections.get(section) or {}
|
||||
totals = block.get("totals") or {}
|
||||
remote_cycle = data.get("cycle") or {}
|
||||
kandang_name = cycle.kandang.kandang_name
|
||||
k_index = kandang_index(kandang_name)
|
||||
masuk_rows = block.get("masuk") or []
|
||||
tuang_rows = block.get("tuang") or []
|
||||
|
||||
in_today = int(totals.get("masuk") or 0)
|
||||
out_today = int(totals.get("tuang") or 0)
|
||||
feed_use_today = out_today
|
||||
in_today = _karung_for_source(masuk_rows, f"K{k_index} - In")
|
||||
feed_use_today = _karung_for_source(tuang_rows, f"K{k_index} - Use")
|
||||
out_today = _karung_for_source(masuk_rows, f"K{k_index} - Out")
|
||||
saldo_awal = int(remote_cycle.get("saldo_awal") or 0)
|
||||
|
||||
snapshot_raw = block.get("date")
|
||||
@@ -166,6 +188,17 @@ def request_karung(
|
||||
"section": section,
|
||||
"snapshot_date": snapshot_date.isoformat(),
|
||||
"totals": totals,
|
||||
"kandang": kandang_name,
|
||||
"kandang_sources": {
|
||||
"in": source_for_kandang(kandang_name, kind="In"),
|
||||
"use": source_for_kandang(kandang_name, kind="Use"),
|
||||
"out": source_for_kandang(kandang_name, kind="Out"),
|
||||
},
|
||||
"kandang_totals": {
|
||||
"in_today": in_today,
|
||||
"feed_use_today": feed_use_today,
|
||||
"out_today": out_today,
|
||||
},
|
||||
"saldo_awal": saldo_awal,
|
||||
"remote_cycle": remote_cycle,
|
||||
}
|
||||
|
||||
@@ -4,13 +4,37 @@ from unittest.mock import patch
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.test import TestCase, override_settings
|
||||
|
||||
from apps.accounts.models import User
|
||||
from apps.farms.models import Cycle, Kandang, Site
|
||||
from apps.operations.services.karung_web import (
|
||||
KarungWebError,
|
||||
fetch_iot_masuk_for_date,
|
||||
initial_balance_accuracy,
|
||||
masuk_source_for_kandang,
|
||||
request_karung,
|
||||
source_for_kandang,
|
||||
)
|
||||
|
||||
ACTIVE_SECTIONS_SAMPLE = {
|
||||
"sections": {
|
||||
"today": {
|
||||
"date": "2026-09-02",
|
||||
"masuk": [
|
||||
{"karung": 192, "source": "K1 - In"},
|
||||
{"karung": 2, "source": "K1 - Out"},
|
||||
{"karung": 120, "source": "K2 - In"},
|
||||
{"karung": 5, "source": "K2 - Out"},
|
||||
],
|
||||
"tuang": [
|
||||
{"karung": 7, "source": "K1 - Use"},
|
||||
{"karung": 9, "source": "K2 - Use"},
|
||||
],
|
||||
"totals": {"masuk": 312, "tuang": 16},
|
||||
}
|
||||
},
|
||||
"cycle": {"saldo_awal": 240},
|
||||
}
|
||||
|
||||
COMBINED_SAMPLE = {
|
||||
"masuk": {
|
||||
"history": [
|
||||
@@ -31,6 +55,8 @@ class MasukSourceForKandangTests(TestCase):
|
||||
def test_maps_kandang_number_to_iot_source(self):
|
||||
self.assertEqual(masuk_source_for_kandang("Kandang 1"), "K1 - In")
|
||||
self.assertEqual(masuk_source_for_kandang("Kandang 2"), "K2 - In")
|
||||
self.assertEqual(source_for_kandang("Kandang 2", kind="Use"), "K2 - Use")
|
||||
self.assertEqual(source_for_kandang("Kandang 2", kind="Out"), "K2 - Out")
|
||||
|
||||
def test_rejects_kandang_name_without_number(self):
|
||||
with self.assertRaises(ValidationError):
|
||||
@@ -97,3 +123,46 @@ class KarungWebCombinedTests(TestCase):
|
||||
def test_fetch_iot_masuk_for_date_propagates_upstream_errors(self, _mock_fetch):
|
||||
with self.assertRaises(KarungWebError):
|
||||
fetch_iot_masuk_for_date(date(2026, 8, 27), kandang_name="Kandang 1")
|
||||
|
||||
|
||||
@override_settings(KARUNG_WEB_ADMIN_BASE_URL="http://karung.internal")
|
||||
class RequestKarungTests(TestCase):
|
||||
def setUp(self):
|
||||
user = User.objects.create_user(user_name="tester", password="secret")
|
||||
site = Site.objects.create(site_name="Sukawarna", user=user)
|
||||
self.kandang1 = Kandang.objects.create(kandang_name="Kandang 1", site=site)
|
||||
self.kandang2 = Kandang.objects.create(kandang_name="Kandang 2", site=site)
|
||||
self.cycle1 = Cycle.objects.create(
|
||||
kandang=self.kandang1,
|
||||
total_days=35,
|
||||
start_date=date(2026, 9, 2),
|
||||
end_date=date(2026, 10, 5),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=10000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
self.cycle2 = Cycle.objects.create(
|
||||
kandang=self.kandang2,
|
||||
total_days=35,
|
||||
start_date=date(2026, 9, 2),
|
||||
end_date=date(2026, 10, 5),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=10000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
|
||||
@patch("apps.operations.services.karung_web.KarungWebClient.fetch_active_sections")
|
||||
def test_request_karung_uses_per_kandang_sources_not_aggregate_totals(self, mock_fetch):
|
||||
mock_fetch.return_value = ACTIVE_SECTIONS_SAMPLE
|
||||
|
||||
feed_sack1, summary1 = request_karung(self.cycle1, section="today")
|
||||
feed_sack2, summary2 = request_karung(self.cycle2, section="today")
|
||||
|
||||
self.assertEqual(feed_sack1.in_today, 192)
|
||||
self.assertEqual(feed_sack1.feed_use_today, 7)
|
||||
self.assertEqual(feed_sack1.out_today, 2)
|
||||
self.assertEqual(feed_sack2.in_today, 120)
|
||||
self.assertEqual(feed_sack2.feed_use_today, 9)
|
||||
self.assertEqual(feed_sack2.out_today, 5)
|
||||
self.assertEqual(summary1["kandang_totals"]["in_today"], 192)
|
||||
self.assertEqual(summary2["kandang_totals"]["in_today"], 120)
|
||||
Reference in new issue
Block a user