add chicken counting, mortality api for daily data sync. Also adjust karung sync to sync every 30 sec after publish cutoff time to update real data without clicking sync button manually

This commit is contained in:
Alberto-Audrix committed 2026-09-04 15:32:18 +07:00
1 parent 5ae477a99d
commit 6c21af745d
17 files changed
+791 -119

No files matched your search

+41
View File
@@ -28,6 +28,10 @@ from apps.operations.serializers import (
ManualInputSerializer,
)
from apps.operations.services.karung_web import KarungWebError, sync_karung_for_cycle
from apps.operations.services.chicken_counting_edge import (
ChickenCountingEdgeError,
sync_chicken_counting_for_cycle,
)
from apps.operations.services.visibility import dashboard_publish_time, visible_through_date
READ_ACTIONS = frozenset({"list", "retrieve", "latest_average", "latest", "dates"})
@@ -70,14 +74,51 @@ class ManualInputViewSet(CycleScopedViewSet):
class ChickenCountingViewSet(CycleScopedViewSet):
"""Chicken counting + mortality IoT — not subject to dashboard publish cutoff."""
queryset = ChickenCounting.objects.select_related("cycle").all()
serializer_class = ChickenCountingSerializer
def applies_visibility_filter(self) -> bool:
return False
@action(detail=False, methods=["post"], url_path="sync")
def sync_from_edge(self, request):
cycle_id = request.data.get("cycle_id")
if not cycle_id:
return Response(
{"detail": "cycle_id is required."},
status=status.HTTP_400_BAD_REQUEST,
)
try:
cycle = Cycle.objects.select_related("kandang").get(pk=cycle_id)
except Cycle.DoesNotExist:
return Response({"detail": "Cycle not found."}, status=status.HTTP_404_NOT_FOUND)
try:
summary = sync_chicken_counting_for_cycle(cycle)
except (ChickenCountingEdgeError, ValidationError) as exc:
code = getattr(exc, "status_code", None)
return Response(
{"detail": str(exc)},
status=code if code and code >= 400 else status.HTTP_502_BAD_GATEWAY,
)
return Response(
{
"upserted": summary["upserted"],
"dates": [d.isoformat() for d in summary["dates"]],
}
)
class ChickenWeightViewSet(CycleScopedViewSet):
"""Chicken weight — not subject to dashboard publish cutoff."""
queryset = ChickenWeight.objects.select_related("cycle").all()
serializer_class = ChickenWeightSerializer
def applies_visibility_filter(self) -> bool:
return False
@action(detail=False, methods=["get"], url_path="latest-avg")
def latest_average(self, request):
cycle_id = request.query_params.get("cycle_id")