# -*- coding: utf-8; -*-
################################################################################
#
# WuttaFarm --Web app to integrate with and extend farmOS
# Copyright © 2026 Lance Edgar
#
# This file is part of WuttaFarm.
#
# WuttaFarm is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# WuttaFarm is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# WuttaFarm. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Master view for Farm Animals
"""
import datetime
import colander
from webhelpers2.html import tags
from wuttaweb.forms.schema import WuttaDateTime, WuttaDictEnum
from wuttaweb.forms.widgets import WuttaDateTimeWidget
from wuttafarm.web.views.farmos.assets import AssetMasterView
from wuttafarm.web.grids import (
SimpleSorter,
StringFilter,
BooleanFilter,
NullableBooleanFilter,
DateTimeFilter,
)
from wuttafarm.web.forms.schema import FarmOSRef
[docs]
class AnimalView(AssetMasterView):
"""
Master view for Farm Animals
"""
model_name = "farmos_animal_assets"
model_title = "farmOS Animal Asset"
model_title_plural = "farmOS Animal Assets"
route_prefix = "farmos_animal_assets"
url_prefix = "/farmOS/assets/animal"
farmos_asset_type = "animal"
farmos_refurl_path = "/assets/animal"
labels = {
"animal_type": "Species / Breed",
"animal_type_name": "Species / Breed",
"is_sterile": "Sterile",
}
grid_columns = [
"thumbnail",
"drupal_id",
"name",
"produces_eggs",
"animal_type_name",
"birthdate",
"is_sterile",
"sex",
"groups",
"owners",
"locations",
"archived",
]
form_fields = [
"name",
"animal_type",
"birthdate",
"produces_eggs",
"sex",
"is_sterile",
"notes",
"asset_type_name",
"owners",
"locations",
"groups",
"archived",
"thumbnail_url",
"image_url",
"thumbnail",
"image",
]
def get_farmos_api_includes(self):
includes = super().get_farmos_api_includes()
includes.update(["animal_type"])
return includes
def render_animal_type_for_grid(self, animal, field, value):
uuid = animal["animal_type"]["uuid"]
url = self.request.route_url("farmos_animal_types.view", uuid=uuid)
return tags.link_to(value, url)
[docs]
def get_instance(self):
data = super().get_instance()
if relationships := self.raw_json["data"].get("relationships"):
# add animal type
if not data.get("animal_type"):
if animal_type := relationships.get("animal_type"):
if animal_type["data"]:
animal_type = self.farmos_client.resource.get_id(
"taxonomy_term", "animal_type", animal_type["data"]["id"]
)
data["animal_type"] = {
"uuid": animal_type["data"]["id"],
"name": animal_type["data"]["attributes"]["name"],
}
return data
def normalize_asset(self, animal, included):
normal = super().normalize_asset(animal, included)
birthdate = animal["attributes"]["birthdate"]
if birthdate:
birthdate = datetime.datetime.fromisoformat(birthdate)
birthdate = self.app.localtime(birthdate)
sterile = None
if self.farmos_4x:
sterile = animal["attributes"]["is_sterile"]
else:
sterile = animal["attributes"]["is_castrated"]
animal_type_object = None
if relationships := animal.get("relationships"):
if animal_type := relationships.get("animal_type"):
if animal_type := included.get(animal_type["data"]["id"]):
animal_type_object = {
"uuid": animal_type["id"],
"name": animal_type["attributes"]["name"],
}
normal.update(
{
"animal_type": animal_type_object,
"animal_type_uuid": animal_type_object["uuid"],
"animal_type_name": animal_type_object["name"],
"birthdate": birthdate,
"sex": animal["attributes"]["sex"] or colander.null,
"is_sterile": sterile,
"produces_eggs": animal["attributes"].get("produces_eggs"),
}
)
return normal
def get_animal_types(self):
animal_types = []
result = self.farmos_client.resource.get(
"taxonomy_term", "animal_type", params={"sort": "name"}
)
for animal_type in result["data"]:
animal_types.append((animal_type["id"], animal_type["attributes"]["name"]))
return animal_types
def get_api_payload(self, animal):
payload = super().get_api_payload(animal)
birthdate = None
if animal["birthdate"]:
birthdate = self.app.localtime(animal["birthdate"]).timestamp()
attrs = {
"sex": animal["sex"] or None,
"is_sterile": animal["is_sterile"],
"produces_eggs": animal["produces_eggs"],
"birthdate": birthdate,
}
rels = {
"animal_type": {
"data": {
"id": animal["animal_type"],
"type": "taxonomy_term--animal_type",
}
}
}
payload["attributes"].update(attrs)
payload.setdefault("relationships", {}).update(rels)
return payload
def defaults(config, **kwargs):
base = globals()
AnimalView = kwargs.get("AnimalView", base["AnimalView"])
AnimalView.defaults(config)
def includeme(config):
defaults(config)