feat: add Standard Quantities table, views, import
This commit is contained in:
parent
c93660ec4a
commit
cfe2e4b7b4
13 changed files with 1225 additions and 131 deletions
|
|
@ -0,0 +1,293 @@
|
|||
"""add Standard Quantities
|
||||
|
||||
Revision ID: 5b6c87d8cddf
|
||||
Revises: 1f98d27cabeb
|
||||
Create Date: 2026-02-19 15:42:19.691148
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
import wuttjamaican.db.util
|
||||
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "5b6c87d8cddf"
|
||||
down_revision: Union[str, None] = "1f98d27cabeb"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
|
||||
# measure
|
||||
op.create_table(
|
||||
"measure",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("name", sa.String(length=100), nullable=False),
|
||||
sa.Column("drupal_id", sa.String(length=20), nullable=True),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_measure")),
|
||||
sa.UniqueConstraint("drupal_id", name=op.f("uq_measure_drupal_id")),
|
||||
sa.UniqueConstraint("name", name=op.f("uq_measure_name")),
|
||||
)
|
||||
op.create_table(
|
||||
"measure_version",
|
||||
sa.Column(
|
||||
"uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column("name", sa.String(length=100), autoincrement=False, nullable=True),
|
||||
sa.Column(
|
||||
"drupal_id", sa.String(length=20), autoincrement=False, nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"transaction_id", sa.BigInteger(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column("end_transaction_id", sa.BigInteger(), nullable=True),
|
||||
sa.Column("operation_type", sa.SmallInteger(), nullable=False),
|
||||
sa.PrimaryKeyConstraint(
|
||||
"uuid", "transaction_id", name=op.f("pk_measure_version")
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_measure_version_end_transaction_id"),
|
||||
"measure_version",
|
||||
["end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_measure_version_operation_type"),
|
||||
"measure_version",
|
||||
["operation_type"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_measure_version_pk_transaction_id",
|
||||
"measure_version",
|
||||
["uuid", sa.literal_column("transaction_id DESC")],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_measure_version_pk_validity",
|
||||
"measure_version",
|
||||
["uuid", "transaction_id", "end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_measure_version_transaction_id"),
|
||||
"measure_version",
|
||||
["transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# quantity
|
||||
op.create_table(
|
||||
"quantity",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("quantity_type_id", sa.String(length=50), nullable=False),
|
||||
sa.Column("measure_id", sa.String(length=20), nullable=False),
|
||||
sa.Column("value_numerator", sa.Integer(), nullable=False),
|
||||
sa.Column("value_denominator", sa.Integer(), nullable=False),
|
||||
sa.Column("units_uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.Column("label", sa.String(length=255), nullable=True),
|
||||
sa.Column("farmos_uuid", wuttjamaican.db.util.UUID(), nullable=True),
|
||||
sa.Column("drupal_id", sa.Integer(), nullable=True),
|
||||
sa.ForeignKeyConstraint(
|
||||
["measure_id"],
|
||||
["measure.drupal_id"],
|
||||
name=op.f("fk_quantity_measure_id_measure"),
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["quantity_type_id"],
|
||||
["quantity_type.drupal_id"],
|
||||
name=op.f("fk_quantity_quantity_type_id_quantity_type"),
|
||||
),
|
||||
sa.ForeignKeyConstraint(
|
||||
["units_uuid"], ["unit.uuid"], name=op.f("fk_quantity_units_uuid_unit")
|
||||
),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_quantity")),
|
||||
sa.UniqueConstraint("drupal_id", name=op.f("uq_quantity_drupal_id")),
|
||||
sa.UniqueConstraint("farmos_uuid", name=op.f("uq_quantity_farmos_uuid")),
|
||||
)
|
||||
op.create_table(
|
||||
"quantity_version",
|
||||
sa.Column(
|
||||
"uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column(
|
||||
"quantity_type_id", sa.String(length=50), autoincrement=False, nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"measure_id", sa.String(length=20), autoincrement=False, nullable=True
|
||||
),
|
||||
sa.Column("value_numerator", sa.Integer(), autoincrement=False, nullable=True),
|
||||
sa.Column(
|
||||
"value_denominator", sa.Integer(), autoincrement=False, nullable=True
|
||||
),
|
||||
sa.Column(
|
||||
"units_uuid",
|
||||
wuttjamaican.db.util.UUID(),
|
||||
autoincrement=False,
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("label", sa.String(length=255), autoincrement=False, nullable=True),
|
||||
sa.Column(
|
||||
"farmos_uuid",
|
||||
wuttjamaican.db.util.UUID(),
|
||||
autoincrement=False,
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("drupal_id", sa.Integer(), autoincrement=False, nullable=True),
|
||||
sa.Column(
|
||||
"transaction_id", sa.BigInteger(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column("end_transaction_id", sa.BigInteger(), nullable=True),
|
||||
sa.Column("operation_type", sa.SmallInteger(), nullable=False),
|
||||
sa.PrimaryKeyConstraint(
|
||||
"uuid", "transaction_id", name=op.f("pk_quantity_version")
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_version_end_transaction_id"),
|
||||
"quantity_version",
|
||||
["end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_version_operation_type"),
|
||||
"quantity_version",
|
||||
["operation_type"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_quantity_version_pk_transaction_id",
|
||||
"quantity_version",
|
||||
["uuid", sa.literal_column("transaction_id DESC")],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_quantity_version_pk_validity",
|
||||
"quantity_version",
|
||||
["uuid", "transaction_id", "end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_version_transaction_id"),
|
||||
"quantity_version",
|
||||
["transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
# quantity_standard
|
||||
op.create_table(
|
||||
"quantity_standard",
|
||||
sa.Column("uuid", wuttjamaican.db.util.UUID(), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
["uuid"], ["quantity.uuid"], name=op.f("fk_quantity_standard_uuid_quantity")
|
||||
),
|
||||
sa.PrimaryKeyConstraint("uuid", name=op.f("pk_quantity_standard")),
|
||||
)
|
||||
op.create_table(
|
||||
"quantity_standard_version",
|
||||
sa.Column(
|
||||
"uuid", wuttjamaican.db.util.UUID(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column(
|
||||
"transaction_id", sa.BigInteger(), autoincrement=False, nullable=False
|
||||
),
|
||||
sa.Column("end_transaction_id", sa.BigInteger(), nullable=True),
|
||||
sa.Column("operation_type", sa.SmallInteger(), nullable=False),
|
||||
sa.PrimaryKeyConstraint(
|
||||
"uuid", "transaction_id", name=op.f("pk_quantity_standard_version")
|
||||
),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_standard_version_end_transaction_id"),
|
||||
"quantity_standard_version",
|
||||
["end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_standard_version_operation_type"),
|
||||
"quantity_standard_version",
|
||||
["operation_type"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_quantity_standard_version_pk_transaction_id",
|
||||
"quantity_standard_version",
|
||||
["uuid", sa.literal_column("transaction_id DESC")],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
"ix_quantity_standard_version_pk_validity",
|
||||
"quantity_standard_version",
|
||||
["uuid", "transaction_id", "end_transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_quantity_standard_version_transaction_id"),
|
||||
"quantity_standard_version",
|
||||
["transaction_id"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
|
||||
# quantity_standard
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_standard_version_transaction_id"),
|
||||
table_name="quantity_standard_version",
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_quantity_standard_version_pk_validity",
|
||||
table_name="quantity_standard_version",
|
||||
)
|
||||
op.drop_index(
|
||||
"ix_quantity_standard_version_pk_transaction_id",
|
||||
table_name="quantity_standard_version",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_standard_version_operation_type"),
|
||||
table_name="quantity_standard_version",
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_standard_version_end_transaction_id"),
|
||||
table_name="quantity_standard_version",
|
||||
)
|
||||
op.drop_table("quantity_standard_version")
|
||||
op.drop_table("quantity_standard")
|
||||
|
||||
# quantity
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_version_transaction_id"), table_name="quantity_version"
|
||||
)
|
||||
op.drop_index("ix_quantity_version_pk_validity", table_name="quantity_version")
|
||||
op.drop_index(
|
||||
"ix_quantity_version_pk_transaction_id", table_name="quantity_version"
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_version_operation_type"), table_name="quantity_version"
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_quantity_version_end_transaction_id"), table_name="quantity_version"
|
||||
)
|
||||
op.drop_table("quantity_version")
|
||||
op.drop_table("quantity")
|
||||
|
||||
# measure
|
||||
op.drop_index(
|
||||
op.f("ix_measure_version_transaction_id"), table_name="measure_version"
|
||||
)
|
||||
op.drop_index("ix_measure_version_pk_validity", table_name="measure_version")
|
||||
op.drop_index("ix_measure_version_pk_transaction_id", table_name="measure_version")
|
||||
op.drop_index(
|
||||
op.f("ix_measure_version_operation_type"), table_name="measure_version"
|
||||
)
|
||||
op.drop_index(
|
||||
op.f("ix_measure_version_end_transaction_id"), table_name="measure_version"
|
||||
)
|
||||
op.drop_table("measure_version")
|
||||
op.drop_table("measure")
|
||||
|
|
@ -30,8 +30,8 @@ from wuttjamaican.db.model import *
|
|||
from .users import WuttaFarmUser
|
||||
|
||||
# wuttafarm proper models
|
||||
from .unit import Unit
|
||||
from .quantities import QuantityType
|
||||
from .unit import Unit, Measure
|
||||
from .quantities import QuantityType, Quantity, StandardQuantity
|
||||
from .asset import AssetType, Asset, AssetParent
|
||||
from .asset_land import LandType, LandAsset
|
||||
from .asset_structure import StructureType, StructureAsset
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ Model definition for Quantities
|
|||
"""
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy.ext.declarative import declared_attr
|
||||
|
||||
from wuttjamaican.db import model
|
||||
|
||||
|
|
@ -79,3 +81,141 @@ class QuantityType(model.Base):
|
|||
|
||||
def __str__(self):
|
||||
return self.name or ""
|
||||
|
||||
|
||||
class Quantity(model.Base):
|
||||
"""
|
||||
Represents a base quantity record from farmOS
|
||||
"""
|
||||
|
||||
__tablename__ = "quantity"
|
||||
__versioned__ = {}
|
||||
__wutta_hint__ = {
|
||||
"model_title": "Quantity",
|
||||
"model_title_plural": "All Quantities",
|
||||
}
|
||||
|
||||
uuid = model.uuid_column()
|
||||
|
||||
quantity_type_id = sa.Column(
|
||||
sa.String(length=50),
|
||||
sa.ForeignKey("quantity_type.drupal_id"),
|
||||
nullable=False,
|
||||
)
|
||||
|
||||
quantity_type = orm.relationship(QuantityType)
|
||||
|
||||
measure_id = sa.Column(
|
||||
sa.String(length=20),
|
||||
sa.ForeignKey("measure.drupal_id"),
|
||||
nullable=False,
|
||||
doc="""
|
||||
Measure for the quantity.
|
||||
""",
|
||||
)
|
||||
|
||||
measure = orm.relationship("Measure")
|
||||
|
||||
value_numerator = sa.Column(
|
||||
sa.Integer(),
|
||||
nullable=False,
|
||||
doc="""
|
||||
Numerator for the quantity value.
|
||||
""",
|
||||
)
|
||||
|
||||
value_denominator = sa.Column(
|
||||
sa.Integer(),
|
||||
nullable=False,
|
||||
doc="""
|
||||
Denominator for the quantity value.
|
||||
""",
|
||||
)
|
||||
|
||||
units_uuid = model.uuid_fk_column("unit.uuid", nullable=False)
|
||||
units = orm.relationship("Unit")
|
||||
|
||||
label = sa.Column(
|
||||
sa.String(length=255),
|
||||
nullable=True,
|
||||
doc="""
|
||||
Optional label for the quantity.
|
||||
""",
|
||||
)
|
||||
|
||||
farmos_uuid = sa.Column(
|
||||
model.UUID(),
|
||||
nullable=True,
|
||||
unique=True,
|
||||
doc="""
|
||||
UUID for the quantity within farmOS.
|
||||
""",
|
||||
)
|
||||
|
||||
drupal_id = sa.Column(
|
||||
sa.Integer(),
|
||||
nullable=True,
|
||||
unique=True,
|
||||
doc="""
|
||||
Drupal internal ID for the quantity.
|
||||
""",
|
||||
)
|
||||
|
||||
def render_as_text(self, config=None):
|
||||
measure = str(self.measure or self.measure_id or "")
|
||||
value = self.value_numerator / self.value_denominator
|
||||
if config:
|
||||
app = config.get_app()
|
||||
value = app.render_quantity(value)
|
||||
units = str(self.units or "")
|
||||
return f"( {measure} ) {value} {units}"
|
||||
|
||||
def __str__(self):
|
||||
return self.render_as_text()
|
||||
|
||||
|
||||
class QuantityMixin:
|
||||
|
||||
uuid = model.uuid_fk_column("quantity.uuid", nullable=False, primary_key=True)
|
||||
|
||||
@declared_attr
|
||||
def quantity(cls):
|
||||
return orm.relationship(Quantity)
|
||||
|
||||
def render_as_text(self, config=None):
|
||||
return self.quantity.render_as_text(config)
|
||||
|
||||
def __str__(self):
|
||||
return self.render_as_text()
|
||||
|
||||
|
||||
def add_quantity_proxies(subclass):
|
||||
Quantity.make_proxy(subclass, "quantity", "farmos_uuid")
|
||||
Quantity.make_proxy(subclass, "quantity", "drupal_id")
|
||||
Quantity.make_proxy(subclass, "quantity", "quantity_type")
|
||||
Quantity.make_proxy(subclass, "quantity", "quantity_type_id")
|
||||
Quantity.make_proxy(subclass, "quantity", "measure")
|
||||
Quantity.make_proxy(subclass, "quantity", "measure_id")
|
||||
Quantity.make_proxy(subclass, "quantity", "value_numerator")
|
||||
Quantity.make_proxy(subclass, "quantity", "value_denominator")
|
||||
Quantity.make_proxy(subclass, "quantity", "value_decimal")
|
||||
Quantity.make_proxy(subclass, "quantity", "units_uuid")
|
||||
Quantity.make_proxy(subclass, "quantity", "units")
|
||||
Quantity.make_proxy(subclass, "quantity", "label")
|
||||
|
||||
|
||||
class StandardQuantity(QuantityMixin, model.Base):
|
||||
"""
|
||||
Represents a Standard Quantity from farmOS
|
||||
"""
|
||||
|
||||
__tablename__ = "quantity_standard"
|
||||
__versioned__ = {}
|
||||
__wutta_hint__ = {
|
||||
"model_title": "Standard Quantity",
|
||||
"model_title_plural": "Standard Quantities",
|
||||
"farmos_quantity_type": "standard",
|
||||
}
|
||||
|
||||
|
||||
add_quantity_proxies(StandardQuantity)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,42 @@ import sqlalchemy as sa
|
|||
from wuttjamaican.db import model
|
||||
|
||||
|
||||
class Measure(model.Base):
|
||||
"""
|
||||
Represents a "measure" option (for quantities) from farmOS
|
||||
"""
|
||||
|
||||
__tablename__ = "measure"
|
||||
__versioned__ = {}
|
||||
__wutta_hint__ = {
|
||||
"model_title": "Measure",
|
||||
"model_title_plural": "Measures",
|
||||
}
|
||||
|
||||
uuid = model.uuid_column()
|
||||
|
||||
name = sa.Column(
|
||||
sa.String(length=100),
|
||||
nullable=False,
|
||||
unique=True,
|
||||
doc="""
|
||||
Name of the measure.
|
||||
""",
|
||||
)
|
||||
|
||||
drupal_id = sa.Column(
|
||||
sa.String(length=20),
|
||||
nullable=True,
|
||||
unique=True,
|
||||
doc="""
|
||||
Drupal internal ID for the measure.
|
||||
""",
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name or ""
|
||||
|
||||
|
||||
class Unit(model.Base):
|
||||
"""
|
||||
Represents an "unit" (taxonomy term) from farmOS
|
||||
|
|
|
|||
|
|
@ -106,8 +106,10 @@ class FromFarmOSToWuttaFarm(FromFarmOSHandler, ToWuttaFarmHandler):
|
|||
importers["GroupAsset"] = GroupAssetImporter
|
||||
importers["PlantType"] = PlantTypeImporter
|
||||
importers["PlantAsset"] = PlantAssetImporter
|
||||
importers["Measure"] = MeasureImporter
|
||||
importers["Unit"] = UnitImporter
|
||||
importers["QuantityType"] = QuantityTypeImporter
|
||||
importers["StandardQuantity"] = StandardQuantityImporter
|
||||
importers["LogType"] = LogTypeImporter
|
||||
importers["ActivityLog"] = ActivityLogImporter
|
||||
importers["HarvestLog"] = HarvestLogImporter
|
||||
|
|
@ -823,6 +825,37 @@ class UserImporter(FromFarmOS, ToWutta):
|
|||
##############################
|
||||
|
||||
|
||||
class MeasureImporter(FromFarmOS, ToWutta):
|
||||
"""
|
||||
farmOS API → WuttaFarm importer for Measures
|
||||
"""
|
||||
|
||||
model_class = model.Measure
|
||||
|
||||
key = "drupal_id"
|
||||
|
||||
supported_fields = [
|
||||
"drupal_id",
|
||||
"name",
|
||||
]
|
||||
|
||||
def get_source_objects(self):
|
||||
""" """
|
||||
response = self.farmos_client.session.get(
|
||||
self.app.get_farmos_url("/api/quantity/standard/resource/schema")
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
return data["definitions"]["attributes"]["properties"]["measure"]["oneOf"]
|
||||
|
||||
def normalize_source_object(self, measure):
|
||||
""" """
|
||||
return {
|
||||
"drupal_id": measure["const"],
|
||||
"name": measure["title"],
|
||||
}
|
||||
|
||||
|
||||
class UnitImporter(FromFarmOS, ToWutta):
|
||||
"""
|
||||
farmOS API → WuttaFarm importer for Units
|
||||
|
|
@ -1100,3 +1133,114 @@ class ObservationLogImporter(LogImporterBase):
|
|||
"status",
|
||||
"assets",
|
||||
]
|
||||
|
||||
|
||||
class QuantityImporterBase(FromFarmOS, ToWutta):
|
||||
"""
|
||||
Base class for farmOS API → WuttaFarm quantity importers
|
||||
"""
|
||||
|
||||
def get_farmos_quantity_type(self):
|
||||
return self.model_class.__wutta_hint__["farmos_quantity_type"]
|
||||
|
||||
def get_simple_fields(self):
|
||||
""" """
|
||||
fields = list(super().get_simple_fields())
|
||||
# nb. must explicitly declare proxy fields
|
||||
fields.extend(
|
||||
[
|
||||
"farmos_uuid",
|
||||
"drupal_id",
|
||||
"quantity_type_id",
|
||||
"measure_id",
|
||||
"value_numerator",
|
||||
"value_denominator",
|
||||
"units_uuid",
|
||||
"label",
|
||||
]
|
||||
)
|
||||
return fields
|
||||
|
||||
def setup(self):
|
||||
super().setup()
|
||||
model = self.app.model
|
||||
|
||||
self.quantity_types_by_farmos_uuid = {}
|
||||
for quantity_type in self.target_session.query(model.QuantityType):
|
||||
if quantity_type.farmos_uuid:
|
||||
self.quantity_types_by_farmos_uuid[quantity_type.farmos_uuid] = (
|
||||
quantity_type
|
||||
)
|
||||
|
||||
self.units_by_farmos_uuid = {}
|
||||
for unit in self.target_session.query(model.Unit):
|
||||
if unit.farmos_uuid:
|
||||
self.units_by_farmos_uuid[unit.farmos_uuid] = unit
|
||||
|
||||
def get_source_objects(self):
|
||||
""" """
|
||||
quantity_type = self.get_farmos_quantity_type()
|
||||
result = self.farmos_client.resource.get("quantity", quantity_type)
|
||||
return result["data"]
|
||||
|
||||
def normalize_source_object(self, quantity):
|
||||
""" """
|
||||
quantity_type_id = None
|
||||
units_uuid = None
|
||||
if relationships := quantity.get("relationships"):
|
||||
|
||||
if quantity_type := relationships.get("quantity_type"):
|
||||
if quantity_type["data"]:
|
||||
if wf_quantity_type := self.quantity_types_by_farmos_uuid.get(
|
||||
UUID(quantity_type["data"]["id"])
|
||||
):
|
||||
quantity_type_id = wf_quantity_type.drupal_id
|
||||
|
||||
if units := relationships.get("units"):
|
||||
if units["data"]:
|
||||
if wf_unit := self.units_by_farmos_uuid.get(
|
||||
UUID(units["data"]["id"])
|
||||
):
|
||||
units_uuid = wf_unit.uuid
|
||||
|
||||
if not quantity_type_id:
|
||||
log.warning(
|
||||
"missing/invalid quantity_type for farmOS Quantity: %s", quantity
|
||||
)
|
||||
return None
|
||||
|
||||
if not units_uuid:
|
||||
log.warning("missing/invalid units for farmOS Quantity: %s", quantity)
|
||||
return None
|
||||
|
||||
value = quantity["attributes"]["value"]
|
||||
|
||||
return {
|
||||
"farmos_uuid": UUID(quantity["id"]),
|
||||
"drupal_id": quantity["attributes"]["drupal_internal__id"],
|
||||
"quantity_type_id": quantity_type_id,
|
||||
"measure_id": quantity["attributes"]["measure"],
|
||||
"value_numerator": value["numerator"],
|
||||
"value_denominator": value["denominator"],
|
||||
"units_uuid": units_uuid,
|
||||
"label": quantity["attributes"]["label"],
|
||||
}
|
||||
|
||||
|
||||
class StandardQuantityImporter(QuantityImporterBase):
|
||||
"""
|
||||
farmOS API → WuttaFarm importer for Standard Quantities
|
||||
"""
|
||||
|
||||
model_class = model.StandardQuantity
|
||||
|
||||
supported_fields = [
|
||||
"farmos_uuid",
|
||||
"drupal_id",
|
||||
"quantity_type_id",
|
||||
"measure_id",
|
||||
"value_numerator",
|
||||
"value_denominator",
|
||||
"units_uuid",
|
||||
"label",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -55,6 +55,26 @@ class AnimalTypeRef(ObjectRef):
|
|||
return self.request.route_url("animal_types.view", uuid=animal_type.uuid)
|
||||
|
||||
|
||||
class FarmOSRef(colander.SchemaType):
|
||||
|
||||
def __init__(self, request, route_prefix, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
self.route_prefix = route_prefix
|
||||
|
||||
def serialize(self, node, appstruct):
|
||||
if appstruct is colander.null:
|
||||
return colander.null
|
||||
|
||||
return json.dumps(appstruct)
|
||||
|
||||
def widget_maker(self, **kwargs):
|
||||
""" """
|
||||
from wuttafarm.web.forms.widgets import FarmOSRefWidget
|
||||
|
||||
return FarmOSRefWidget(self.request, self.route_prefix, **kwargs)
|
||||
|
||||
|
||||
class AnimalTypeType(colander.SchemaType):
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
|
|
@ -179,6 +199,27 @@ class StructureTypeRef(ObjectRef):
|
|||
return self.request.route_url("structure_types.view", uuid=structure_type.uuid)
|
||||
|
||||
|
||||
class UnitRef(ObjectRef):
|
||||
"""
|
||||
Custom schema type for a :class:`~wuttafarm.db.model.units.Unit`
|
||||
reference field.
|
||||
|
||||
This is a subclass of
|
||||
:class:`~wuttaweb:wuttaweb.forms.schema.ObjectRef`.
|
||||
"""
|
||||
|
||||
@property
|
||||
def model_class(self):
|
||||
model = self.app.model
|
||||
return model.Unit
|
||||
|
||||
def sort_query(self, query):
|
||||
return query.order_by(self.model_class.name)
|
||||
|
||||
def get_object_url(self, unit):
|
||||
return self.request.route_url("units.view", uuid=unit.uuid)
|
||||
|
||||
|
||||
class UsersType(colander.SchemaType):
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
|
|
|
|||
|
|
@ -54,6 +54,33 @@ class ImageWidget(Widget):
|
|||
return super().serialize(field, cstruct, **kw)
|
||||
|
||||
|
||||
class FarmOSRefWidget(Widget):
|
||||
"""
|
||||
Generic widget to display "any reference field" - as a link to
|
||||
view the farmOS record it references. Only used by the farmOS
|
||||
direct API views.
|
||||
"""
|
||||
|
||||
def __init__(self, request, route_prefix, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
self.route_prefix = route_prefix
|
||||
|
||||
def serialize(self, field, cstruct, **kw):
|
||||
readonly = kw.get("readonly", self.readonly)
|
||||
if readonly:
|
||||
if cstruct in (colander.null, None):
|
||||
return HTML.tag("span")
|
||||
|
||||
obj = json.loads(cstruct)
|
||||
return tags.link_to(
|
||||
obj["name"],
|
||||
self.request.route_url(f"{self.route_prefix}.view", uuid=obj["uuid"]),
|
||||
)
|
||||
|
||||
return super().serialize(field, cstruct, **kw)
|
||||
|
||||
|
||||
class AnimalTypeWidget(Widget):
|
||||
"""
|
||||
Widget to display an "animal type" field.
|
||||
|
|
|
|||
|
|
@ -134,11 +134,27 @@ class WuttaFarmMenuHandler(base.MenuHandler):
|
|||
"perm": "logs_observation.list",
|
||||
},
|
||||
{"type": "sep"},
|
||||
{
|
||||
"title": "All Quantities",
|
||||
"route": "quantities",
|
||||
"perm": "quantities.list",
|
||||
},
|
||||
{
|
||||
"title": "Standard Quantities",
|
||||
"route": "quantities_standard",
|
||||
"perm": "quantities_standard.list",
|
||||
},
|
||||
{"type": "sep"},
|
||||
{
|
||||
"title": "Log Types",
|
||||
"route": "log_types",
|
||||
"perm": "log_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Measures",
|
||||
"route": "measures",
|
||||
"perm": "measures.list",
|
||||
},
|
||||
{
|
||||
"title": "Quantity Types",
|
||||
"route": "quantity_types",
|
||||
|
|
@ -248,6 +264,11 @@ class WuttaFarmMenuHandler(base.MenuHandler):
|
|||
"route": "farmos_quantity_types",
|
||||
"perm": "farmos_quantity_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Standard Quantities",
|
||||
"route": "farmos_quantities_standard",
|
||||
"perm": "farmos_quantities_standard.list",
|
||||
},
|
||||
{
|
||||
"title": "Units",
|
||||
"route": "farmos_units",
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ from .master import FarmOSMasterView
|
|||
|
||||
def includeme(config):
|
||||
config.include("wuttafarm.web.views.farmos.users")
|
||||
config.include("wuttafarm.web.views.farmos.quantity_types")
|
||||
config.include("wuttafarm.web.views.farmos.quantities")
|
||||
config.include("wuttafarm.web.views.farmos.asset_types")
|
||||
config.include("wuttafarm.web.views.farmos.units")
|
||||
config.include("wuttafarm.web.views.farmos.land_types")
|
||||
|
|
|
|||
278
src/wuttafarm/web/views/farmos/quantities.py
Normal file
278
src/wuttafarm/web/views/farmos/quantities.py
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
# -*- 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
View for farmOS Quantity Types
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
import colander
|
||||
|
||||
from wuttaweb.forms.schema import WuttaDateTime
|
||||
from wuttaweb.forms.widgets import WuttaDateTimeWidget
|
||||
|
||||
from wuttafarm.web.views.farmos import FarmOSMasterView
|
||||
from wuttafarm.web.forms.schema import FarmOSRef
|
||||
|
||||
|
||||
class QuantityTypeView(FarmOSMasterView):
|
||||
"""
|
||||
View for farmOS Quantity Types
|
||||
"""
|
||||
|
||||
model_name = "farmos_quantity_type"
|
||||
model_title = "farmOS Quantity Type"
|
||||
model_title_plural = "farmOS Quantity Types"
|
||||
|
||||
route_prefix = "farmos_quantity_types"
|
||||
url_prefix = "/farmOS/quantity-types"
|
||||
|
||||
grid_columns = [
|
||||
"label",
|
||||
"description",
|
||||
]
|
||||
|
||||
sort_defaults = "label"
|
||||
|
||||
form_fields = [
|
||||
"label",
|
||||
"description",
|
||||
]
|
||||
|
||||
def get_grid_data(self, columns=None, session=None):
|
||||
result = self.farmos_client.resource.get("quantity_type")
|
||||
return [self.normalize_quantity_type(t) for t in result["data"]]
|
||||
|
||||
def configure_grid(self, grid):
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
|
||||
# label
|
||||
g.set_link("label")
|
||||
g.set_searchable("label")
|
||||
|
||||
# description
|
||||
g.set_searchable("description")
|
||||
|
||||
def get_instance(self):
|
||||
result = self.farmos_client.resource.get_id(
|
||||
"quantity_type", "quantity_type", self.request.matchdict["uuid"]
|
||||
)
|
||||
self.raw_json = result
|
||||
return self.normalize_quantity_type(result["data"])
|
||||
|
||||
def get_instance_title(self, quantity_type):
|
||||
return quantity_type["label"]
|
||||
|
||||
def normalize_quantity_type(self, quantity_type):
|
||||
return {
|
||||
"uuid": quantity_type["id"],
|
||||
"drupal_id": quantity_type["attributes"]["drupal_internal__id"],
|
||||
"label": quantity_type["attributes"]["label"],
|
||||
"description": quantity_type["attributes"]["description"],
|
||||
}
|
||||
|
||||
def configure_form(self, form):
|
||||
f = form
|
||||
super().configure_form(f)
|
||||
|
||||
# description
|
||||
f.set_widget("description", "notes")
|
||||
|
||||
def get_xref_buttons(self, quantity_type):
|
||||
model = self.app.model
|
||||
session = self.Session()
|
||||
buttons = []
|
||||
|
||||
if wf_quantity_type := (
|
||||
session.query(model.QuantityType)
|
||||
.filter(model.QuantityType.farmos_uuid == quantity_type["uuid"])
|
||||
.first()
|
||||
):
|
||||
buttons.append(
|
||||
self.make_button(
|
||||
f"View {self.app.get_title()} record",
|
||||
primary=True,
|
||||
url=self.request.route_url(
|
||||
"quantity_types.view", uuid=wf_quantity_type.uuid
|
||||
),
|
||||
icon_left="eye",
|
||||
)
|
||||
)
|
||||
|
||||
return buttons
|
||||
|
||||
|
||||
class QuantityMasterView(FarmOSMasterView):
|
||||
"""
|
||||
Base class for Quantity views
|
||||
"""
|
||||
|
||||
farmos_quantity_type = None
|
||||
|
||||
grid_columns = [
|
||||
"measure",
|
||||
"value",
|
||||
"label",
|
||||
"changed",
|
||||
]
|
||||
|
||||
sort_defaults = ("changed", "desc")
|
||||
|
||||
form_fields = [
|
||||
"measure",
|
||||
"value",
|
||||
"units",
|
||||
"label",
|
||||
"created",
|
||||
"changed",
|
||||
]
|
||||
|
||||
def get_grid_data(self, columns=None, session=None):
|
||||
result = self.farmos_client.resource.get("quantity", self.farmos_quantity_type)
|
||||
return [self.normalize_quantity(t) for t in result["data"]]
|
||||
|
||||
def configure_grid(self, grid):
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
|
||||
# value
|
||||
g.set_link("value")
|
||||
|
||||
# changed
|
||||
g.set_renderer("changed", "datetime")
|
||||
|
||||
def get_instance(self):
|
||||
quantity = self.farmos_client.resource.get_id(
|
||||
"quantity", self.farmos_quantity_type, self.request.matchdict["uuid"]
|
||||
)
|
||||
self.raw_json = quantity
|
||||
|
||||
data = self.normalize_quantity(quantity["data"])
|
||||
|
||||
if relationships := quantity["data"].get("relationships"):
|
||||
|
||||
# add units
|
||||
if units := relationships.get("units"):
|
||||
if units["data"]:
|
||||
unit = self.farmos_client.resource.get_id(
|
||||
"taxonomy_term", "unit", units["data"]["id"]
|
||||
)
|
||||
data["units"] = {
|
||||
"uuid": unit["data"]["id"],
|
||||
"name": unit["data"]["attributes"]["name"],
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
def get_instance_title(self, quantity):
|
||||
return quantity["value"]
|
||||
|
||||
def normalize_quantity(self, quantity):
|
||||
|
||||
if created := quantity["attributes"]["created"]:
|
||||
created = datetime.datetime.fromisoformat(created)
|
||||
created = self.app.localtime(created)
|
||||
|
||||
if changed := quantity["attributes"]["changed"]:
|
||||
changed = datetime.datetime.fromisoformat(changed)
|
||||
changed = self.app.localtime(changed)
|
||||
|
||||
return {
|
||||
"uuid": quantity["id"],
|
||||
"drupal_id": quantity["attributes"]["drupal_internal__id"],
|
||||
"measure": quantity["attributes"]["measure"],
|
||||
"value": quantity["attributes"]["value"],
|
||||
"label": quantity["attributes"]["label"] or colander.null,
|
||||
"created": created,
|
||||
"changed": changed,
|
||||
}
|
||||
|
||||
def configure_form(self, form):
|
||||
f = form
|
||||
super().configure_form(f)
|
||||
|
||||
# created
|
||||
f.set_node("created", WuttaDateTime(self.request))
|
||||
f.set_widget("created", WuttaDateTimeWidget(self.request))
|
||||
|
||||
# changed
|
||||
f.set_node("changed", WuttaDateTime(self.request))
|
||||
f.set_widget("changed", WuttaDateTimeWidget(self.request))
|
||||
|
||||
# units
|
||||
f.set_node("units", FarmOSRef(self.request, "farmos_units"))
|
||||
|
||||
|
||||
class StandardQuantityView(QuantityMasterView):
|
||||
"""
|
||||
View for farmOS Standard Quantities
|
||||
"""
|
||||
|
||||
model_name = "farmos_standard_quantity"
|
||||
model_title = "farmOS Standard Quantity"
|
||||
model_title_plural = "farmOS Standard Quantities"
|
||||
|
||||
route_prefix = "farmos_quantities_standard"
|
||||
url_prefix = "/farmOS/quantities/standard"
|
||||
|
||||
farmos_quantity_type = "standard"
|
||||
|
||||
def get_xref_buttons(self, standard_quantity):
|
||||
model = self.app.model
|
||||
session = self.Session()
|
||||
buttons = []
|
||||
|
||||
if wf_standard_quantity := (
|
||||
session.query(model.StandardQuantity)
|
||||
.join(model.Quantity)
|
||||
.filter(model.Quantity.farmos_uuid == standard_quantity["uuid"])
|
||||
.first()
|
||||
):
|
||||
buttons.append(
|
||||
self.make_button(
|
||||
f"View {self.app.get_title()} record",
|
||||
primary=True,
|
||||
url=self.request.route_url(
|
||||
"quantities_standard.view", uuid=wf_standard_quantity.uuid
|
||||
),
|
||||
icon_left="eye",
|
||||
)
|
||||
)
|
||||
|
||||
return buttons
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
QuantityTypeView = kwargs.get("QuantityTypeView", base["QuantityTypeView"])
|
||||
QuantityTypeView.defaults(config)
|
||||
|
||||
StandardQuantityView = kwargs.get(
|
||||
"StandardQuantityView", base["StandardQuantityView"]
|
||||
)
|
||||
StandardQuantityView.defaults(config)
|
||||
|
||||
|
||||
def includeme(config):
|
||||
defaults(config)
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
# -*- 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
View for farmOS Quantity Types
|
||||
"""
|
||||
|
||||
from wuttafarm.web.views.farmos import FarmOSMasterView
|
||||
|
||||
|
||||
class QuantityTypeView(FarmOSMasterView):
|
||||
"""
|
||||
View for farmOS Quantity Types
|
||||
"""
|
||||
|
||||
model_name = "farmos_quantity_type"
|
||||
model_title = "farmOS Quantity Type"
|
||||
model_title_plural = "farmOS Quantity Types"
|
||||
|
||||
route_prefix = "farmos_quantity_types"
|
||||
url_prefix = "/farmOS/quantity-types"
|
||||
|
||||
grid_columns = [
|
||||
"label",
|
||||
"description",
|
||||
]
|
||||
|
||||
sort_defaults = "label"
|
||||
|
||||
form_fields = [
|
||||
"label",
|
||||
"description",
|
||||
]
|
||||
|
||||
def get_grid_data(self, columns=None, session=None):
|
||||
result = self.farmos_client.resource.get("quantity_type")
|
||||
return [self.normalize_quantity_type(t) for t in result["data"]]
|
||||
|
||||
def configure_grid(self, grid):
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
|
||||
# label
|
||||
g.set_link("label")
|
||||
g.set_searchable("label")
|
||||
|
||||
# description
|
||||
g.set_searchable("description")
|
||||
|
||||
def get_instance(self):
|
||||
result = self.farmos_client.resource.get_id(
|
||||
"quantity_type", "quantity_type", self.request.matchdict["uuid"]
|
||||
)
|
||||
self.raw_json = result
|
||||
return self.normalize_quantity_type(result["data"])
|
||||
|
||||
def get_instance_title(self, quantity_type):
|
||||
return quantity_type["label"]
|
||||
|
||||
def normalize_quantity_type(self, quantity_type):
|
||||
return {
|
||||
"uuid": quantity_type["id"],
|
||||
"drupal_id": quantity_type["attributes"]["drupal_internal__id"],
|
||||
"label": quantity_type["attributes"]["label"],
|
||||
"description": quantity_type["attributes"]["description"],
|
||||
}
|
||||
|
||||
def configure_form(self, form):
|
||||
f = form
|
||||
super().configure_form(f)
|
||||
|
||||
# description
|
||||
f.set_widget("description", "notes")
|
||||
|
||||
def get_xref_buttons(self, quantity_type):
|
||||
model = self.app.model
|
||||
session = self.Session()
|
||||
buttons = []
|
||||
|
||||
if wf_quantity_type := (
|
||||
session.query(model.QuantityType)
|
||||
.filter(model.QuantityType.farmos_uuid == quantity_type["uuid"])
|
||||
.first()
|
||||
):
|
||||
buttons.append(
|
||||
self.make_button(
|
||||
f"View {self.app.get_title()} record",
|
||||
primary=True,
|
||||
url=self.request.route_url(
|
||||
"quantity_types.view", uuid=wf_quantity_type.uuid
|
||||
),
|
||||
icon_left="eye",
|
||||
)
|
||||
)
|
||||
|
||||
return buttons
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
QuantityTypeView = kwargs.get("QuantityTypeView", base["QuantityTypeView"])
|
||||
QuantityTypeView.defaults(config)
|
||||
|
||||
|
||||
def includeme(config):
|
||||
defaults(config)
|
||||
|
|
@ -23,8 +23,24 @@
|
|||
Master view for Quantities
|
||||
"""
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
from wuttaweb.db import Session
|
||||
|
||||
from wuttafarm.web.views import WuttaFarmMasterView
|
||||
from wuttafarm.db.model import QuantityType
|
||||
from wuttafarm.db.model import QuantityType, Quantity, StandardQuantity
|
||||
from wuttafarm.web.forms.schema import UnitRef
|
||||
|
||||
|
||||
def get_quantity_type_enum(config):
|
||||
app = config.get_app()
|
||||
model = app.model
|
||||
session = Session()
|
||||
quantity_types = OrderedDict()
|
||||
query = session.query(model.QuantityType).order_by(model.QuantityType.name)
|
||||
for quantity_type in query:
|
||||
quantity_types[quantity_type.drupal_id] = quantity_type.name
|
||||
return quantity_types
|
||||
|
||||
|
||||
class QuantityTypeView(WuttaFarmMasterView):
|
||||
|
|
@ -79,12 +95,199 @@ class QuantityTypeView(WuttaFarmMasterView):
|
|||
return buttons
|
||||
|
||||
|
||||
class QuantityMasterView(WuttaFarmMasterView):
|
||||
"""
|
||||
Base class for Quantity master views
|
||||
"""
|
||||
|
||||
grid_columns = [
|
||||
"drupal_id",
|
||||
"as_text",
|
||||
"quantity_type",
|
||||
"measure",
|
||||
"value",
|
||||
"units",
|
||||
"label",
|
||||
]
|
||||
|
||||
sort_defaults = ("drupal_id", "desc")
|
||||
|
||||
form_fields = [
|
||||
"quantity_type",
|
||||
"as_text",
|
||||
"measure",
|
||||
"value",
|
||||
"units",
|
||||
"label",
|
||||
"farmos_uuid",
|
||||
"drupal_id",
|
||||
]
|
||||
|
||||
def get_query(self, session=None):
|
||||
""" """
|
||||
model = self.app.model
|
||||
model_class = self.get_model_class()
|
||||
session = session or self.Session()
|
||||
query = session.query(model_class)
|
||||
if model_class is not model.Quantity:
|
||||
query = query.join(model.Quantity)
|
||||
query = query.join(model.Measure).join(model.Unit)
|
||||
return query
|
||||
|
||||
def configure_grid(self, grid):
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
model = self.app.model
|
||||
model_class = self.get_model_class()
|
||||
|
||||
# drupal_id
|
||||
g.set_label("drupal_id", "ID", column_only=True)
|
||||
g.set_sorter("drupal_id", model.Quantity.drupal_id)
|
||||
|
||||
# as_text
|
||||
g.set_renderer("as_text", self.render_as_text_for_grid)
|
||||
g.set_link("as_text")
|
||||
|
||||
# quantity_type
|
||||
if model_class is not model.Quantity:
|
||||
g.remove("quantity_type")
|
||||
else:
|
||||
g.set_enum("quantity_type", get_quantity_type_enum(self.config))
|
||||
|
||||
# measure
|
||||
g.set_sorter("measure", model.Measure.name)
|
||||
|
||||
# value
|
||||
g.set_renderer("value", self.render_value_for_grid)
|
||||
|
||||
# units
|
||||
g.set_sorter("units", model.Unit.name)
|
||||
|
||||
# label
|
||||
g.set_sorter("label", model.Quantity.label)
|
||||
|
||||
# view action links to final quantity record
|
||||
if model_class is model.Quantity:
|
||||
|
||||
def quantity_url(quantity, i):
|
||||
return self.request.route_url(
|
||||
f"quantities_{quantity.quantity_type_id}.view", uuid=quantity.uuid
|
||||
)
|
||||
|
||||
g.add_action("view", icon="eye", url=quantity_url)
|
||||
|
||||
def render_as_text_for_grid(self, quantity, field, value):
|
||||
return quantity.render_as_text(self.config)
|
||||
|
||||
def render_value_for_grid(self, quantity, field, value):
|
||||
value = quantity.value_numerator / quantity.value_denominator
|
||||
return self.app.render_quantity(value)
|
||||
|
||||
def get_instance_title(self, quantity):
|
||||
return quantity.render_as_text(self.config)
|
||||
|
||||
def configure_form(self, form):
|
||||
f = form
|
||||
super().configure_form(f)
|
||||
quantity = form.model_instance
|
||||
|
||||
# as_text
|
||||
if self.creating or self.editing:
|
||||
f.remove("as_text")
|
||||
else:
|
||||
f.set_default("as_text", quantity.render_as_text(self.config))
|
||||
|
||||
# quantity_type
|
||||
if self.creating:
|
||||
f.remove("quantity_type")
|
||||
else:
|
||||
f.set_readonly("quantity_type")
|
||||
f.set_default("quantity_type", quantity.quantity_type.name)
|
||||
|
||||
# measure
|
||||
if self.creating:
|
||||
f.remove("measure")
|
||||
else:
|
||||
f.set_readonly("measure")
|
||||
f.set_default("measure", quantity.measure.name)
|
||||
|
||||
# value
|
||||
if self.creating:
|
||||
f.remove("value")
|
||||
else:
|
||||
value = quantity.value_numerator / quantity.value_denominator
|
||||
value = self.app.render_quantity(value)
|
||||
f.set_default(
|
||||
"value",
|
||||
f"{value} ({quantity.value_numerator} / {quantity.value_denominator})",
|
||||
)
|
||||
|
||||
# units
|
||||
if self.creating:
|
||||
f.remove("units")
|
||||
else:
|
||||
f.set_readonly("units")
|
||||
f.set_node("units", UnitRef(self.request))
|
||||
# TODO: ugh
|
||||
f.set_default("units", quantity.quantity.units)
|
||||
|
||||
def get_xref_buttons(self, quantity):
|
||||
buttons = super().get_xref_buttons(quantity)
|
||||
|
||||
if quantity.farmos_uuid:
|
||||
url = self.request.route_url(
|
||||
f"farmos_quantities_{quantity.quantity_type_id}.view",
|
||||
uuid=quantity.farmos_uuid,
|
||||
)
|
||||
buttons.append(
|
||||
self.make_button(
|
||||
"View farmOS record", primary=True, url=url, icon_left="eye"
|
||||
)
|
||||
)
|
||||
|
||||
return buttons
|
||||
|
||||
|
||||
class QuantityView(QuantityMasterView):
|
||||
"""
|
||||
Master view for All Quantities
|
||||
"""
|
||||
|
||||
model_class = Quantity
|
||||
route_prefix = "quantities"
|
||||
url_prefix = "/quantities"
|
||||
|
||||
viewable = False
|
||||
creatable = False
|
||||
editable = False
|
||||
deletable = False
|
||||
model_is_versioned = False
|
||||
|
||||
|
||||
class StandardQuantityView(QuantityMasterView):
|
||||
"""
|
||||
Master view for Standard Quantities
|
||||
"""
|
||||
|
||||
model_class = StandardQuantity
|
||||
route_prefix = "quantities_standard"
|
||||
url_prefix = "/quantities/standard"
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
QuantityTypeView = kwargs.get("QuantityTypeView", base["QuantityTypeView"])
|
||||
QuantityTypeView.defaults(config)
|
||||
|
||||
QuantityView = kwargs.get("QuantityView", base["QuantityView"])
|
||||
QuantityView.defaults(config)
|
||||
|
||||
StandardQuantityView = kwargs.get(
|
||||
"StandardQuantityView", base["StandardQuantityView"]
|
||||
)
|
||||
StandardQuantityView.defaults(config)
|
||||
|
||||
|
||||
def includeme(config):
|
||||
defaults(config)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,40 @@ Master view for Units
|
|||
"""
|
||||
|
||||
from wuttafarm.web.views import WuttaFarmMasterView
|
||||
from wuttafarm.db.model import Unit
|
||||
from wuttafarm.db.model import Measure, Unit
|
||||
|
||||
|
||||
class MeasureView(WuttaFarmMasterView):
|
||||
"""
|
||||
Master view for Measures
|
||||
"""
|
||||
|
||||
model_class = Measure
|
||||
route_prefix = "measures"
|
||||
url_prefix = "/measures"
|
||||
|
||||
grid_columns = [
|
||||
"name",
|
||||
"drupal_id",
|
||||
]
|
||||
|
||||
sort_defaults = "name"
|
||||
|
||||
filter_defaults = {
|
||||
"name": {"active": True, "verb": "contains"},
|
||||
}
|
||||
|
||||
form_fields = [
|
||||
"name",
|
||||
"drupal_id",
|
||||
]
|
||||
|
||||
def configure_grid(self, grid):
|
||||
g = grid
|
||||
super().configure_grid(g)
|
||||
|
||||
# name
|
||||
g.set_link("name")
|
||||
|
||||
|
||||
class UnitView(WuttaFarmMasterView):
|
||||
|
|
@ -34,7 +67,7 @@ class UnitView(WuttaFarmMasterView):
|
|||
|
||||
model_class = Unit
|
||||
route_prefix = "units"
|
||||
url_prefix = "/animal-types"
|
||||
url_prefix = "/units"
|
||||
|
||||
farmos_refurl_path = "/admin/structure/taxonomy/manage/unit/overview"
|
||||
|
||||
|
|
@ -87,6 +120,9 @@ class UnitView(WuttaFarmMasterView):
|
|||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
||||
MeasureView = kwargs.get("MeasureView", base["MeasureView"])
|
||||
MeasureView.defaults(config)
|
||||
|
||||
UnitView = kwargs.get("UnitView", base["UnitView"])
|
||||
UnitView.defaults(config)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue