remove wagtail and admin website, remove edit option, from hitung ayam, add create flock to settings
This commit is contained in:
1 parent
74dd3faf60
commit
30a736641f
39 files changed
+634
-819
No files matched your search
@@ -1,8 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from apps.farms.models import Cycle, Flock, Kandang, Site
|
||||
|
||||
admin.site.register(Site)
|
||||
admin.site.register(Kandang)
|
||||
admin.site.register(Flock)
|
||||
admin.site.register(Cycle)
|
||||
@@ -0,0 +1,50 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def backfill_flock_kandang(apps, schema_editor):
|
||||
Flock = apps.get_model("farms", "Flock")
|
||||
for flock in Flock.objects.select_related("cycle").iterator():
|
||||
if flock.cycle_id and flock.kandang_id is None:
|
||||
flock.kandang_id = flock.cycle.kandang_id
|
||||
flock.save(update_fields=["kandang_id"])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("farms", "0008_cycle_feed_initial_balance"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="flock",
|
||||
name="kandang",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flocks",
|
||||
to="farms.kandang",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(backfill_flock_kandang, migrations.RunPython.noop),
|
||||
migrations.AlterField(
|
||||
model_name="flock",
|
||||
name="kandang",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flocks",
|
||||
to="farms.kandang",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="flock",
|
||||
name="cycle",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="flocks",
|
||||
to="farms.cycle",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,32 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def remove_orphan_flocks(apps, schema_editor):
|
||||
Flock = apps.get_model("farms", "Flock")
|
||||
Flock.objects.filter(cycle_id__isnull=True).delete()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
("farms", "0009_flock_belongs_to_kandang"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(remove_orphan_flocks, migrations.RunPython.noop),
|
||||
migrations.RemoveField(
|
||||
model_name="flock",
|
||||
name="kandang",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="flock",
|
||||
name="cycle",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flocks",
|
||||
to="farms.cycle",
|
||||
),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,45 @@
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
def backfill_flock_kandang_from_cycle(apps, schema_editor):
|
||||
Flock = apps.get_model("farms", "Flock")
|
||||
for flock in Flock.objects.select_related("cycle").iterator():
|
||||
if flock.cycle_id and flock.kandang_id is None:
|
||||
flock.kandang_id = flock.cycle.kandang_id
|
||||
flock.save(update_fields=["kandang_id"])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
atomic = False
|
||||
|
||||
dependencies = [
|
||||
("farms", "0010_restore_flock_cycle_erd"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="flock",
|
||||
name="kandang",
|
||||
field=models.ForeignKey(
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flocks",
|
||||
to="farms.kandang",
|
||||
),
|
||||
),
|
||||
migrations.RunPython(backfill_flock_kandang_from_cycle, migrations.RunPython.noop),
|
||||
migrations.AlterField(
|
||||
model_name="flock",
|
||||
name="kandang",
|
||||
field=models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="flocks",
|
||||
to="farms.kandang",
|
||||
),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="flock",
|
||||
name="cycle",
|
||||
),
|
||||
]
|
||||
@@ -2,13 +2,10 @@ from datetime import date
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from wagtail.admin.panels import FieldPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
from apps.accounts.models import User
|
||||
|
||||
|
||||
@register_snippet
|
||||
class Site(models.Model):
|
||||
site_id = models.BigAutoField(primary_key=True)
|
||||
site_name = models.CharField(max_length=30)
|
||||
@@ -16,11 +13,6 @@ class Site(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel("site_name"),
|
||||
FieldPanel("user"),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
db_table = "sites"
|
||||
ordering = ["site_name"]
|
||||
@@ -29,7 +21,6 @@ class Site(models.Model):
|
||||
return self.site_name
|
||||
|
||||
|
||||
@register_snippet
|
||||
class Kandang(models.Model):
|
||||
kandang_id = models.BigAutoField(primary_key=True)
|
||||
kandang_name = models.CharField(max_length=30)
|
||||
@@ -37,11 +28,6 @@ class Kandang(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel("kandang_name"),
|
||||
FieldPanel("site"),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
db_table = "kandang"
|
||||
ordering = ["kandang_name"]
|
||||
@@ -50,23 +36,17 @@ class Kandang(models.Model):
|
||||
return self.kandang_name
|
||||
|
||||
|
||||
@register_snippet
|
||||
class Flock(models.Model):
|
||||
flock_id = models.BigAutoField(primary_key=True)
|
||||
flock_name = models.CharField(max_length=30)
|
||||
cycle = models.ForeignKey(
|
||||
"Cycle",
|
||||
kandang = models.ForeignKey(
|
||||
Kandang,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="flocks",
|
||||
)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel("flock_name"),
|
||||
FieldPanel("cycle"),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
db_table = "flock"
|
||||
ordering = ["flock_name"]
|
||||
@@ -75,7 +55,6 @@ class Flock(models.Model):
|
||||
return self.flock_name
|
||||
|
||||
|
||||
@register_snippet
|
||||
class Cycle(models.Model):
|
||||
STATUS_ACTIVE = "active"
|
||||
STATUS_CLOSED = "closed"
|
||||
@@ -98,17 +77,6 @@ class Cycle(models.Model):
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
panels = [
|
||||
FieldPanel("kandang"),
|
||||
FieldPanel("total_days"),
|
||||
FieldPanel("start_date"),
|
||||
FieldPanel("end_date"),
|
||||
FieldPanel("doc_in_weight"),
|
||||
FieldPanel("doc_in_count"),
|
||||
FieldPanel("feed_initial_balance"),
|
||||
FieldPanel("status"),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
db_table = "cycles"
|
||||
ordering = ["-start_date"]
|
||||
|
||||
@@ -21,15 +21,13 @@ class KandangSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
||||
class FlockSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Flock
|
||||
fields = ["id", "flock_name", "cycle", "created_at", "updated_at"]
|
||||
fields = ["id", "flock_name", "kandang", "created_at", "updated_at"]
|
||||
read_only_fields = ["id", "created_at", "updated_at"]
|
||||
|
||||
|
||||
class CycleSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
||||
kandang = serializers.PrimaryKeyRelatedField(queryset=Kandang.objects.all())
|
||||
kandang_name = serializers.CharField(source="kandang.kandang_name", read_only=True)
|
||||
flock = serializers.SerializerMethodField()
|
||||
flock_name = serializers.SerializerMethodField()
|
||||
chick_in_weight = serializers.IntegerField(source="doc_in_weight")
|
||||
current_day = serializers.IntegerField(read_only=True)
|
||||
visible_through_date = serializers.DateField(read_only=True)
|
||||
@@ -40,8 +38,6 @@ class CycleSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
||||
"id",
|
||||
"kandang",
|
||||
"kandang_name",
|
||||
"flock",
|
||||
"flock_name",
|
||||
"total_days",
|
||||
"current_day",
|
||||
"visible_through_date",
|
||||
@@ -57,26 +53,7 @@ class CycleSerializer(PkAsIdMixin, serializers.ModelSerializer):
|
||||
read_only_fields = [
|
||||
"id",
|
||||
"kandang_name",
|
||||
"flock",
|
||||
"flock_name",
|
||||
"feed_initial_balance",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
||||
def _first_flock(self, obj):
|
||||
return obj.flocks.order_by("flock_id").first()
|
||||
|
||||
def get_flock(self, obj):
|
||||
flock = self._first_flock(obj)
|
||||
return flock.pk if flock is not None else None
|
||||
|
||||
def get_flock_name(self, obj):
|
||||
flock = self._first_flock(obj)
|
||||
return flock.flock_name if flock is not None else None
|
||||
|
||||
def create(self, validated_data):
|
||||
kandang = validated_data["kandang"]
|
||||
cycle = Cycle.objects.create(**validated_data)
|
||||
Flock.objects.create(flock_name=kandang.kandang_name[:30], cycle=cycle)
|
||||
return cycle
|
||||
+52
-51
@@ -10,12 +10,37 @@ from apps.farms.models import Cycle, Flock, Kandang, Site
|
||||
class FarmAPITests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(user_name="tester", password="secret")
|
||||
self.admin = User.objects.create_user(
|
||||
user_name="admin",
|
||||
password="secret",
|
||||
status=User.STATUS_SUPERADMIN,
|
||||
)
|
||||
self.client = APIClient()
|
||||
self.client.force_authenticate(self.user)
|
||||
self.site = Site.objects.create(site_name="Sukawarna", user=self.user)
|
||||
self.kandang = Kandang.objects.create(kandang_name="Kandang 1", site=self.site)
|
||||
|
||||
def test_create_cycle_auto_creates_flock_and_returns_erd_fields(self):
|
||||
def test_create_flock_under_kandang_requires_superadmin(self):
|
||||
self.client.force_authenticate(self.admin)
|
||||
response = self.client.post(
|
||||
"/api/v1/flocks/",
|
||||
{"flock_name": "Lantai 1", "kandang": self.kandang.pk},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, 201, response.data)
|
||||
self.assertEqual(response.data["flock_name"], "Lantai 1")
|
||||
self.assertEqual(response.data["kandang"], self.kandang.pk)
|
||||
|
||||
def test_staff_cannot_create_flock(self):
|
||||
self.client.force_authenticate(self.user)
|
||||
response = self.client.post(
|
||||
"/api/v1/flocks/",
|
||||
{"flock_name": "Lantai 1", "kandang": self.kandang.pk},
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, 403, response.data)
|
||||
|
||||
def test_create_cycle_without_flock(self):
|
||||
self.client.force_authenticate(self.user)
|
||||
start = date.today()
|
||||
response = self.client.post(
|
||||
"/api/v1/cycles/",
|
||||
@@ -31,56 +56,32 @@ class FarmAPITests(TestCase):
|
||||
format="json",
|
||||
)
|
||||
self.assertEqual(response.status_code, 201, response.data)
|
||||
self.assertEqual(response.data["chick_in_weight"], 42)
|
||||
self.assertEqual(response.data["kandang_name"], "Kandang 1")
|
||||
self.assertEqual(response.data["flock_name"], "Kandang 1")
|
||||
self.assertIsNotNone(response.data["flock"])
|
||||
cycle = Cycle.objects.get(pk=response.data["id"])
|
||||
flock = Flock.objects.get(pk=response.data["flock"])
|
||||
self.assertEqual(cycle.doc_in_weight, 42)
|
||||
self.assertEqual(flock.cycle_id, cycle.pk)
|
||||
self.assertNotIn("flock", response.data)
|
||||
self.assertNotIn("flock_name", response.data)
|
||||
|
||||
def test_list_cycles_by_kandang(self):
|
||||
cycle = Cycle.objects.create(
|
||||
kandang=self.kandang,
|
||||
total_days=35,
|
||||
start_date=date.today(),
|
||||
end_date=date.today() + timedelta(days=34),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=9000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
flock = Flock.objects.create(flock_name="Flock A", cycle=cycle)
|
||||
response = self.client.get("/api/v1/cycles/", {"kandang_id": self.kandang.pk})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
results = response.data["results"] if isinstance(response.data, dict) else response.data
|
||||
self.assertEqual(len(results), 1)
|
||||
self.assertEqual(results[0]["flock"], flock.pk)
|
||||
self.assertEqual(results[0]["kandang_name"], "Kandang 1")
|
||||
self.assertEqual(results[0]["flock_name"], "Flock A")
|
||||
def test_flock_persists_across_cycles(self):
|
||||
flock = Flock.objects.create(flock_name="Lantai 1", kandang=self.kandang)
|
||||
start = date.today()
|
||||
for offset in (0, 40):
|
||||
Cycle.objects.create(
|
||||
kandang=self.kandang,
|
||||
total_days=35,
|
||||
start_date=start + timedelta(days=offset),
|
||||
end_date=start + timedelta(days=offset + 34),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=9000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
self.assertEqual(Flock.objects.filter(kandang=self.kandang).count(), 1)
|
||||
self.assertEqual(flock.kandang_id, self.kandang.pk)
|
||||
|
||||
def test_list_flocks_by_cycle(self):
|
||||
cycle = Cycle.objects.create(
|
||||
kandang=self.kandang,
|
||||
total_days=35,
|
||||
start_date=date.today(),
|
||||
end_date=date.today() + timedelta(days=34),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=9000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
flock = Flock.objects.create(flock_name="Flock A", cycle=cycle)
|
||||
other_cycle = Cycle.objects.create(
|
||||
kandang=self.kandang,
|
||||
total_days=35,
|
||||
start_date=date.today(),
|
||||
end_date=date.today() + timedelta(days=34),
|
||||
doc_in_weight=40,
|
||||
doc_in_count=9000,
|
||||
status=Cycle.STATUS_ACTIVE,
|
||||
)
|
||||
Flock.objects.create(flock_name="Flock B", cycle=other_cycle)
|
||||
response = self.client.get("/api/v1/flocks/", {"cycle_id": cycle.pk})
|
||||
def test_list_flocks_by_kandang(self):
|
||||
self.client.force_authenticate(self.user)
|
||||
Flock.objects.create(flock_name="Lantai 1", kandang=self.kandang)
|
||||
Flock.objects.create(flock_name="Lantai 2", kandang=self.kandang)
|
||||
other_kandang = Kandang.objects.create(kandang_name="Kandang 2", site=self.site)
|
||||
Flock.objects.create(flock_name="Other", kandang=other_kandang)
|
||||
response = self.client.get("/api/v1/flocks/", {"kandang_id": self.kandang.pk})
|
||||
self.assertEqual(response.status_code, 200, response.data)
|
||||
results = response.data["results"] if isinstance(response.data, dict) else response.data
|
||||
self.assertEqual([r["id"] for r in results], [flock.pk])
|
||||
self.assertEqual(len(results), 2)
|
||||
@@ -56,19 +56,20 @@ class KandangViewSet(viewsets.ModelViewSet):
|
||||
|
||||
|
||||
class FlockViewSet(viewsets.ModelViewSet):
|
||||
queryset = Flock.objects.all()
|
||||
queryset = Flock.objects.select_related("kandang").all()
|
||||
serializer_class = FlockSerializer
|
||||
permission_classes = [IsSuperAdminForWrite]
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset()
|
||||
cycle_id = self.request.query_params.get("cycle_id")
|
||||
if cycle_id:
|
||||
qs = qs.filter(cycle_id=cycle_id)
|
||||
kandang_id = self.request.query_params.get("kandang_id")
|
||||
if kandang_id:
|
||||
qs = qs.filter(kandang_id=kandang_id)
|
||||
return qs
|
||||
|
||||
|
||||
class CycleViewSet(viewsets.ModelViewSet):
|
||||
queryset = Cycle.objects.select_related("kandang").prefetch_related("flocks").all()
|
||||
queryset = Cycle.objects.select_related("kandang").all()
|
||||
serializer_class = CycleSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
Reference in new issue
Block a user