feat: add common normalizer to simplify code in view, importer etc.
only the "log" normalizer exists so far, but will add more..
This commit is contained in:
parent
1a6870b8fe
commit
e7ef5c3d32
9 changed files with 331 additions and 208 deletions
|
|
@ -56,24 +56,38 @@ class WuttaFarmAppHandler(base.AppHandler):
|
|||
Returns the integration mode for farmOS, i.e. to control the
|
||||
app's behavior regarding that.
|
||||
"""
|
||||
handler = self.get_farmos_handler()
|
||||
return handler.get_farmos_integration_mode()
|
||||
enum = self.enum
|
||||
return self.config.get(
|
||||
f"{self.appname}.farmos_integration_mode",
|
||||
default=enum.FARMOS_INTEGRATION_MODE_WRAPPER,
|
||||
)
|
||||
|
||||
def is_farmos_mirror(self):
|
||||
"""
|
||||
Returns ``True`` if the app is configured in "mirror"
|
||||
integration mode with regard to farmOS.
|
||||
"""
|
||||
handler = self.get_farmos_handler()
|
||||
return handler.is_farmos_mirror()
|
||||
enum = self.enum
|
||||
mode = self.get_farmos_integration_mode()
|
||||
return mode == enum.FARMOS_INTEGRATION_MODE_MIRROR
|
||||
|
||||
def is_farmos_wrapper(self):
|
||||
"""
|
||||
Returns ``True`` if the app is configured in "wrapper"
|
||||
integration mode with regard to farmOS.
|
||||
"""
|
||||
handler = self.get_farmos_handler()
|
||||
return handler.is_farmos_wrapper()
|
||||
enum = self.enum
|
||||
mode = self.get_farmos_integration_mode()
|
||||
return mode == enum.FARMOS_INTEGRATION_MODE_WRAPPER
|
||||
|
||||
def is_standalone(self):
|
||||
"""
|
||||
Returns ``True`` if the app is configured in "standalone" mode
|
||||
with regard to farmOS.
|
||||
"""
|
||||
enum = self.enum
|
||||
mode = self.get_farmos_integration_mode()
|
||||
return mode == enum.FARMOS_INTEGRATION_MODE_NONE
|
||||
|
||||
def get_farmos_url(self, *args, **kwargs):
|
||||
"""
|
||||
|
|
@ -109,7 +123,20 @@ class WuttaFarmAppHandler(base.AppHandler):
|
|||
handler = self.get_farmos_handler()
|
||||
return handler.is_farmos_4x(*args, **kwargs)
|
||||
|
||||
def export_to_farmos(self, obj, require=True):
|
||||
def get_normalizer(self, farmos_client=None):
|
||||
"""
|
||||
Get the configured farmOS integration handler.
|
||||
|
||||
:rtype: :class:`~wuttafarm.farmos.FarmOSHandler`
|
||||
"""
|
||||
spec = self.config.get(
|
||||
f"{self.appname}.normalizer_spec",
|
||||
default="wuttafarm.normal:Normalizer",
|
||||
)
|
||||
factory = self.load_object(spec)
|
||||
return factory(self.config, farmos_client)
|
||||
|
||||
def auto_sync_to_farmos(self, obj, model_name=None, require=True):
|
||||
"""
|
||||
Export the given object to farmOS, using configured handler.
|
||||
|
||||
|
|
@ -127,6 +154,7 @@ class WuttaFarmAppHandler(base.AppHandler):
|
|||
"""
|
||||
handler = self.app.get_import_handler("export.to_farmos.from_wuttafarm")
|
||||
|
||||
if not model_name:
|
||||
model_name = type(obj).__name__
|
||||
if model_name not in handler.importers:
|
||||
if require:
|
||||
|
|
@ -141,6 +169,37 @@ class WuttaFarmAppHandler(base.AppHandler):
|
|||
normal = importer.normalize_source_object(obj)
|
||||
importer.process_data(source_data=[normal])
|
||||
|
||||
def auto_sync_from_farmos(self, obj, model_name, require=True):
|
||||
"""
|
||||
Import the given object from farmOS, using configured handler.
|
||||
|
||||
:param obj: Any data record from farmOS.
|
||||
|
||||
:param model_name': Model name for the importer to use,
|
||||
e.g. ``"AnimalAsset"``.
|
||||
|
||||
:param require: If true, this will *require* the import
|
||||
handler to support objects of the given type. If false,
|
||||
then nothing will happen / import is silently skipped when
|
||||
there is no such importer.
|
||||
"""
|
||||
handler = self.app.get_import_handler("import.to_wuttafarm.from_farmos")
|
||||
|
||||
if model_name not in handler.importers:
|
||||
if require:
|
||||
raise ValueError(f"no importer found for {model_name}")
|
||||
return
|
||||
|
||||
# nb. begin txn to establish the API client
|
||||
# TODO: should probably use current user oauth2 token instead
|
||||
# of always making a new one here, which is what happens IIUC
|
||||
handler.begin_source_transaction()
|
||||
with self.short_session(commit=True) as session:
|
||||
handler.target_session = session
|
||||
importer = handler.get_importer(model_name, caches_target=False)
|
||||
normal = importer.normalize_source_object(obj)
|
||||
importer.process_data(source_data=[normal])
|
||||
|
||||
|
||||
class WuttaFarmAppProvider(base.AppProvider):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -34,35 +34,6 @@ class FarmOSHandler(GenericHandler):
|
|||
:term:`handler`.
|
||||
"""
|
||||
|
||||
def get_farmos_integration_mode(self):
|
||||
"""
|
||||
Returns the integration mode for farmOS, i.e. to control the
|
||||
app's behavior regarding that.
|
||||
"""
|
||||
enum = self.app.enum
|
||||
return self.config.get(
|
||||
f"{self.app.appname}.farmos_integration_mode",
|
||||
default=enum.FARMOS_INTEGRATION_MODE_WRAPPER,
|
||||
)
|
||||
|
||||
def is_farmos_mirror(self):
|
||||
"""
|
||||
Returns ``True`` if the app is configured in "mirror"
|
||||
integration mode with regard to farmOS.
|
||||
"""
|
||||
enum = self.app.enum
|
||||
mode = self.get_farmos_integration_mode()
|
||||
return mode == enum.FARMOS_INTEGRATION_MODE_MIRROR
|
||||
|
||||
def is_farmos_wrapper(self):
|
||||
"""
|
||||
Returns ``True`` if the app is configured in "wrapper"
|
||||
integration mode with regard to farmOS.
|
||||
"""
|
||||
enum = self.app.enum
|
||||
mode = self.get_farmos_integration_mode()
|
||||
return mode == enum.FARMOS_INTEGRATION_MODE_WRAPPER
|
||||
|
||||
def get_farmos_client(self, hostname=None, **kwargs):
|
||||
"""
|
||||
Returns a new farmOS API client.
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ class FromFarmOSHandler(ImportHandler):
|
|||
token = self.get_farmos_oauth2_token()
|
||||
self.farmos_client = self.app.get_farmos_client(token=token)
|
||||
self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)
|
||||
self.normal = self.app.get_normalizer(self.farmos_client)
|
||||
|
||||
def get_farmos_oauth2_token(self):
|
||||
|
||||
|
|
@ -76,6 +77,7 @@ class FromFarmOSHandler(ImportHandler):
|
|||
kwargs = super().get_importer_kwargs(key, **kwargs)
|
||||
kwargs["farmos_client"] = self.farmos_client
|
||||
kwargs["farmos_4x"] = self.farmos_4x
|
||||
kwargs["normal"] = self.normal
|
||||
return kwargs
|
||||
|
||||
|
||||
|
|
@ -981,33 +983,25 @@ class LogImporterBase(FromFarmOS, ToWutta):
|
|||
def get_source_objects(self):
|
||||
""" """
|
||||
log_type = self.get_farmos_log_type()
|
||||
result = self.farmos_client.log.get(log_type)
|
||||
return result["data"]
|
||||
|
||||
def get_asset_type(self, asset):
|
||||
return asset["type"].split("--")[1]
|
||||
return list(self.farmos_client.log.iterate(log_type))
|
||||
|
||||
def normalize_source_object(self, log):
|
||||
""" """
|
||||
if notes := log["attributes"]["notes"]:
|
||||
notes = notes["value"]
|
||||
data = self.normal.normalize_farmos_log(log)
|
||||
|
||||
data["farmos_uuid"] = UUID(data.pop("uuid"))
|
||||
data["message"] = data.pop("name")
|
||||
data["timestamp"] = self.app.make_utc(data["timestamp"])
|
||||
|
||||
# TODO
|
||||
data["log_type"] = self.get_farmos_log_type()
|
||||
|
||||
assets = None
|
||||
if "assets" in self.fields:
|
||||
assets = []
|
||||
for asset in log["relationships"]["asset"]["data"]:
|
||||
assets.append((self.get_asset_type(asset), UUID(asset["id"])))
|
||||
data["assets"] = [
|
||||
(a["asset_type"], UUID(a["uuid"])) for a in data["assets"]
|
||||
]
|
||||
|
||||
return {
|
||||
"farmos_uuid": UUID(log["id"]),
|
||||
"drupal_id": log["attributes"]["drupal_internal__id"],
|
||||
"log_type": self.get_farmos_log_type(),
|
||||
"message": log["attributes"]["name"],
|
||||
"timestamp": self.normalize_datetime(log["attributes"]["timestamp"]),
|
||||
"notes": notes,
|
||||
"status": log["attributes"]["status"],
|
||||
"assets": assets,
|
||||
}
|
||||
return data
|
||||
|
||||
def normalize_target_object(self, log):
|
||||
data = super().normalize_target_object(log)
|
||||
|
|
@ -1183,6 +1177,28 @@ class QuantityImporterBase(FromFarmOS, ToWutta):
|
|||
result = self.farmos_client.resource.get("quantity", quantity_type)
|
||||
return result["data"]
|
||||
|
||||
def get_quantity_type_by_farmos_uuid(self, uuid):
|
||||
if hasattr(self, "quantity_types_by_farmos_uuid"):
|
||||
return self.quantity_types_by_farmos_uuid.get(UUID(uuid))
|
||||
|
||||
model = self.app.model
|
||||
return (
|
||||
self.target_session.query(model.QuantityType)
|
||||
.filter(model.QuantityType.farmos_uuid == uuid)
|
||||
.one()
|
||||
)
|
||||
|
||||
def get_unit_by_farmos_uuid(self, uuid):
|
||||
if hasattr(self, "units_by_farmos_uuid"):
|
||||
return self.units_by_farmos_uuid.get(UUID(uuid))
|
||||
|
||||
model = self.app.model
|
||||
return (
|
||||
self.target_session.query(model.Unit)
|
||||
.filter(model.Unit.farmos_uuid == uuid)
|
||||
.one()
|
||||
)
|
||||
|
||||
def normalize_source_object(self, quantity):
|
||||
""" """
|
||||
quantity_type_id = None
|
||||
|
|
@ -1191,16 +1207,14 @@ class QuantityImporterBase(FromFarmOS, ToWutta):
|
|||
|
||||
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"])
|
||||
if wf_quantity_type := self.get_quantity_type_by_farmos_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"])
|
||||
):
|
||||
if wf_unit := self.get_unit_by_farmos_uuid(units["data"]["id"]):
|
||||
units_uuid = wf_unit.uuid
|
||||
|
||||
if not quantity_type_id:
|
||||
|
|
|
|||
199
src/wuttafarm/normal.py
Normal file
199
src/wuttafarm/normal.py
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
# -*- 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/>.
|
||||
#
|
||||
################################################################################
|
||||
"""
|
||||
Data normalizer for WuttaFarm / farmOS
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
from wuttjamaican.app import GenericHandler
|
||||
|
||||
|
||||
class Normalizer(GenericHandler):
|
||||
"""
|
||||
Base class and default implementation for the global data
|
||||
normalizer. This should be used for normalizing records from
|
||||
WuttaFarm and/or farmOS.
|
||||
|
||||
The point here is to have a single place to put the normalization
|
||||
logic, and let it be another thing which can be customized via
|
||||
subclass.
|
||||
"""
|
||||
|
||||
_farmos_units = None
|
||||
_farmos_measures = None
|
||||
|
||||
def __init__(self, config, farmos_client=None):
|
||||
super().__init__(config)
|
||||
self.farmos_client = farmos_client
|
||||
|
||||
def get_farmos_measures(self):
|
||||
if self._farmos_measures:
|
||||
return self._farmos_measures
|
||||
|
||||
measures = {}
|
||||
response = self.farmos_client.session.get(
|
||||
self.app.get_farmos_url("/api/quantity/standard/resource/schema")
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
for measure in data["definitions"]["attributes"]["properties"]["measure"][
|
||||
"oneOf"
|
||||
]:
|
||||
measures[measure["const"]] = measure["title"]
|
||||
|
||||
self._farmos_measures = measures
|
||||
return self._farmos_measures
|
||||
|
||||
def get_farmos_measure_name(self, measure_id):
|
||||
measures = self.get_farmos_measures()
|
||||
return measures[measure_id]
|
||||
|
||||
def get_farmos_unit(self, uuid):
|
||||
units = self.get_farmos_units()
|
||||
return units[uuid]
|
||||
|
||||
def get_farmos_units(self):
|
||||
if self._farmos_units:
|
||||
return self._farmos_units
|
||||
|
||||
units = {}
|
||||
result = self.farmos_client.resource.get("taxonomy_term", "unit")
|
||||
for unit in result["data"]:
|
||||
units[unit["id"]] = unit
|
||||
|
||||
self._farmos_units = units
|
||||
return self._farmos_units
|
||||
|
||||
def normalize_farmos_log(self, log, included={}):
|
||||
|
||||
if timestamp := log["attributes"]["timestamp"]:
|
||||
timestamp = datetime.datetime.fromisoformat(timestamp)
|
||||
timestamp = self.app.localtime(timestamp)
|
||||
|
||||
if notes := log["attributes"]["notes"]:
|
||||
notes = notes["value"]
|
||||
|
||||
log_type_object = {}
|
||||
log_type_uuid = None
|
||||
asset_objects = []
|
||||
quantity_objects = []
|
||||
quantity_uuids = []
|
||||
owner_objects = []
|
||||
owner_uuids = []
|
||||
if relationships := log.get("relationships"):
|
||||
|
||||
if log_type := relationships.get("log_type"):
|
||||
log_type_uuid = log_type["data"]["id"]
|
||||
if log_type := included.get(log_type_uuid):
|
||||
log_type_object = {
|
||||
"uuid": log_type["id"],
|
||||
"name": log_type["attributes"]["label"],
|
||||
}
|
||||
|
||||
if assets := relationships.get("asset"):
|
||||
for asset in assets["data"]:
|
||||
asset_object = {
|
||||
"uuid": asset["id"],
|
||||
"type": asset["type"],
|
||||
"asset_type": asset["type"].split("--")[1],
|
||||
}
|
||||
if asset := included.get(asset["id"]):
|
||||
attrs = asset["attributes"]
|
||||
rels = asset["relationships"]
|
||||
asset_object.update(
|
||||
{
|
||||
"drupal_id": attrs["drupal_internal__id"],
|
||||
"name": attrs["name"],
|
||||
"is_location": attrs["is_location"],
|
||||
"is_fixed": attrs["is_fixed"],
|
||||
"archived": attrs["archived"],
|
||||
"notes": attrs["notes"],
|
||||
}
|
||||
)
|
||||
asset_objects.append(asset_object)
|
||||
|
||||
if quantities := relationships.get("quantity"):
|
||||
for quantity in quantities["data"]:
|
||||
quantity_uuid = quantity["id"]
|
||||
quantity_uuids.append(quantity_uuid)
|
||||
if quantity := included.get(quantity_uuid):
|
||||
attrs = quantity["attributes"]
|
||||
rels = quantity["relationships"]
|
||||
value = attrs["value"]
|
||||
|
||||
unit_uuid = rels["units"]["data"]["id"]
|
||||
unit = self.get_farmos_unit(unit_uuid)
|
||||
|
||||
measure_id = attrs["measure"]
|
||||
|
||||
quantity_objects.append(
|
||||
{
|
||||
"uuid": quantity["id"],
|
||||
"drupal_id": attrs["drupal_internal__id"],
|
||||
"quantity_type_uuid": rels["quantity_type"]["data"][
|
||||
"id"
|
||||
],
|
||||
"quantity_type_id": rels["quantity_type"]["data"][
|
||||
"meta"
|
||||
]["drupal_internal__target_id"],
|
||||
"measure_id": measure_id,
|
||||
"measure_name": self.get_farmos_measure_name(
|
||||
measure_id
|
||||
),
|
||||
"value_numerator": value["numerator"],
|
||||
"value_decimal": value["decimal"],
|
||||
"value_denominator": value["denominator"],
|
||||
"unit_uuid": unit_uuid,
|
||||
"unit_name": unit["attributes"]["name"],
|
||||
}
|
||||
)
|
||||
|
||||
if owners := relationships.get("owner"):
|
||||
for user in owners["data"]:
|
||||
user_uuid = user["id"]
|
||||
owner_uuids.append(user_uuid)
|
||||
if user := included.get(user_uuid):
|
||||
owner_objects.append(
|
||||
{
|
||||
"uuid": user["id"],
|
||||
"name": user["attributes"]["name"],
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"uuid": log["id"],
|
||||
"drupal_id": log["attributes"]["drupal_internal__id"],
|
||||
"log_type_uuid": log_type_uuid,
|
||||
"log_type": log_type_object,
|
||||
"name": log["attributes"]["name"],
|
||||
"timestamp": timestamp,
|
||||
"assets": asset_objects,
|
||||
"quantities": quantity_objects,
|
||||
"quantity_uuids": quantity_uuids,
|
||||
"is_group_assignment": log["attributes"]["is_group_assignment"],
|
||||
"quick": log["attributes"]["quick"],
|
||||
"status": log["attributes"]["status"],
|
||||
"notes": notes,
|
||||
"owners": owner_objects,
|
||||
"owner_uuids": owner_uuids,
|
||||
}
|
||||
|
|
@ -23,12 +23,9 @@
|
|||
View for farmOS Harvest Logs
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
import colander
|
||||
from webhelpers2.html import tags
|
||||
|
||||
from wuttaweb.forms.schema import WuttaDateTime, WuttaDictEnum
|
||||
from wuttaweb.forms.schema import WuttaDateTime, WuttaDictEnum, Notes
|
||||
from wuttaweb.forms.widgets import WuttaDateTimeWidget
|
||||
|
||||
from wuttafarm.web.views.farmos import FarmOSMasterView
|
||||
|
|
@ -58,9 +55,6 @@ class LogMasterView(FarmOSMasterView):
|
|||
filterable = True
|
||||
sort_on_backend = True
|
||||
|
||||
_farmos_units = None
|
||||
_farmos_measures = None
|
||||
|
||||
labels = {
|
||||
"name": "Log Name",
|
||||
"log_type_name": "Log Type",
|
||||
|
|
@ -193,141 +187,14 @@ class LogMasterView(FarmOSMasterView):
|
|||
def get_instance_title(self, log):
|
||||
return log["name"]
|
||||
|
||||
def get_farmos_units(self):
|
||||
if self._farmos_units:
|
||||
return self._farmos_units
|
||||
|
||||
units = {}
|
||||
result = self.farmos_client.resource.get("taxonomy_term", "unit")
|
||||
for unit in result["data"]:
|
||||
units[unit["id"]] = unit
|
||||
|
||||
self._farmos_units = units
|
||||
return self._farmos_units
|
||||
|
||||
def get_farmos_unit(self, uuid):
|
||||
units = self.get_farmos_units()
|
||||
return units[uuid]
|
||||
|
||||
def get_farmos_measures(self):
|
||||
if self._farmos_measures:
|
||||
return self._farmos_measures
|
||||
|
||||
measures = {}
|
||||
response = self.farmos_client.session.get(
|
||||
self.app.get_farmos_url("/api/quantity/standard/resource/schema")
|
||||
)
|
||||
response.raise_for_status()
|
||||
data = response.json()
|
||||
for measure in data["definitions"]["attributes"]["properties"]["measure"][
|
||||
"oneOf"
|
||||
]:
|
||||
measures[measure["const"]] = measure["title"]
|
||||
|
||||
self._farmos_measures = measures
|
||||
return self._farmos_measures
|
||||
|
||||
def get_farmos_measure_name(self, measure_id):
|
||||
measures = self.get_farmos_measures()
|
||||
return measures[measure_id]
|
||||
|
||||
def normalize_log(self, log, included):
|
||||
|
||||
if timestamp := log["attributes"]["timestamp"]:
|
||||
timestamp = datetime.datetime.fromisoformat(timestamp)
|
||||
timestamp = self.app.localtime(timestamp)
|
||||
|
||||
if notes := log["attributes"]["notes"]:
|
||||
notes = notes["value"]
|
||||
|
||||
log_type_object = {}
|
||||
log_type_name = None
|
||||
asset_objects = []
|
||||
quantity_objects = []
|
||||
owner_objects = []
|
||||
if relationships := log.get("relationships"):
|
||||
|
||||
if log_type := relationships.get("log_type"):
|
||||
log_type = included[log_type["data"]["id"]]
|
||||
log_type_object = {
|
||||
"uuid": log_type["id"],
|
||||
"name": log_type["attributes"]["label"],
|
||||
}
|
||||
log_type_name = log_type_object["name"]
|
||||
|
||||
if assets := relationships.get("asset"):
|
||||
for asset in assets["data"]:
|
||||
asset = included[asset["id"]]
|
||||
attrs = asset["attributes"]
|
||||
rels = asset["relationships"]
|
||||
asset_objects.append(
|
||||
data = self.normal.normalize_farmos_log(log, included)
|
||||
data.update(
|
||||
{
|
||||
"uuid": asset["id"],
|
||||
"drupal_id": attrs["drupal_internal__id"],
|
||||
"name": attrs["name"],
|
||||
"is_location": attrs["is_location"],
|
||||
"is_fixed": attrs["is_fixed"],
|
||||
"archived": attrs["archived"],
|
||||
"notes": attrs["notes"],
|
||||
"asset_type": asset["type"].split("--")[1],
|
||||
"log_type_name": data["log_type"].get("name"),
|
||||
}
|
||||
)
|
||||
|
||||
if quantities := relationships.get("quantity"):
|
||||
for quantity in quantities["data"]:
|
||||
quantity = included[quantity["id"]]
|
||||
attrs = quantity["attributes"]
|
||||
rels = quantity["relationships"]
|
||||
value = attrs["value"]
|
||||
|
||||
unit_uuid = rels["units"]["data"]["id"]
|
||||
unit = self.get_farmos_unit(unit_uuid)
|
||||
|
||||
measure_id = attrs["measure"]
|
||||
|
||||
quantity_objects.append(
|
||||
{
|
||||
"uuid": quantity["id"],
|
||||
"drupal_id": attrs["drupal_internal__id"],
|
||||
"quantity_type_uuid": rels["quantity_type"]["data"]["id"],
|
||||
"quantity_type_id": rels["quantity_type"]["data"]["meta"][
|
||||
"drupal_internal__target_id"
|
||||
],
|
||||
"measure_id": measure_id,
|
||||
"measure_name": self.get_farmos_measure_name(measure_id),
|
||||
"value_numerator": value["numerator"],
|
||||
"value_decimal": value["decimal"],
|
||||
"value_denominator": value["denominator"],
|
||||
"unit_uuid": unit_uuid,
|
||||
"unit_name": unit["attributes"]["name"],
|
||||
}
|
||||
)
|
||||
|
||||
if owners := relationships.get("owner"):
|
||||
for user in owners["data"]:
|
||||
user = included[user["id"]]
|
||||
owner_objects.append(
|
||||
{
|
||||
"uuid": user["id"],
|
||||
"name": user["attributes"]["name"],
|
||||
}
|
||||
)
|
||||
|
||||
return {
|
||||
"uuid": log["id"],
|
||||
"drupal_id": log["attributes"]["drupal_internal__id"],
|
||||
"log_type": log_type_object,
|
||||
"log_type_name": log_type_name,
|
||||
"name": log["attributes"]["name"],
|
||||
"timestamp": timestamp,
|
||||
"assets": asset_objects,
|
||||
"quantities": quantity_objects,
|
||||
"is_group_assignment": log["attributes"]["is_group_assignment"],
|
||||
"quick": log["attributes"]["quick"],
|
||||
"status": log["attributes"]["status"],
|
||||
"notes": notes or colander.null,
|
||||
"owners": owner_objects,
|
||||
}
|
||||
return data
|
||||
|
||||
def configure_form(self, form):
|
||||
f = form
|
||||
|
|
@ -346,7 +213,7 @@ class LogMasterView(FarmOSMasterView):
|
|||
f.set_node("quantities", FarmOSQuantityRefs(self.request))
|
||||
|
||||
# notes
|
||||
f.set_widget("notes", "notes")
|
||||
f.set_node("notes", Notes())
|
||||
|
||||
# status
|
||||
f.set_node("status", WuttaDictEnum(self.request, enum.LOG_STATUS))
|
||||
|
|
|
|||
|
|
@ -72,6 +72,7 @@ class FarmOSMasterView(MasterView):
|
|||
super().__init__(request, context=context)
|
||||
self.farmos_client = self.get_farmos_client()
|
||||
self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)
|
||||
self.normal = self.app.get_normalizer(self.farmos_client)
|
||||
self.raw_json = None
|
||||
self.farmos_style_grid_links = use_farmos_style_grid_links(self.config)
|
||||
|
||||
|
|
|
|||
|
|
@ -105,4 +105,4 @@ class WuttaFarmMasterView(MasterView):
|
|||
|
||||
def persist(self, obj, session=None):
|
||||
super().persist(obj, session)
|
||||
self.app.export_to_farmos(obj, require=False)
|
||||
self.app.auto_sync_to_farmos(obj, require=False)
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class QuickFormView(View):
|
|||
super().__init__(request, context=context)
|
||||
self.farmos_client = self.get_farmos_client()
|
||||
self.farmos_4x = self.app.is_farmos_4x(self.farmos_client)
|
||||
self.normal = self.app.get_normalizer(self.farmos_client)
|
||||
|
||||
@classmethod
|
||||
def get_route_slug(cls):
|
||||
|
|
|
|||
|
|
@ -112,6 +112,18 @@ class EggsQuickForm(QuickFormView):
|
|||
return assets
|
||||
|
||||
def save_quick_form(self, form):
|
||||
|
||||
response = self.save_to_farmos(form)
|
||||
log = json.loads(response["create-log#body{0}"]["body"])
|
||||
|
||||
if self.app.is_farmos_mirror():
|
||||
quantity = json.loads(response["create-quantity"]["body"])
|
||||
self.app.auto_sync_from_farmos(quantity["data"], "StandardQuantity")
|
||||
self.app.auto_sync_from_farmos(log["data"], "HarvestLog")
|
||||
|
||||
return log
|
||||
|
||||
def save_to_farmos(self, form):
|
||||
data = form.validated
|
||||
|
||||
assets = self.get_layer_assets()
|
||||
|
|
@ -217,8 +229,7 @@ class EggsQuickForm(QuickFormView):
|
|||
blueprints.insert(0, new_unit)
|
||||
blueprint = SubrequestsBlueprint.parse_obj(blueprints)
|
||||
response = self.farmos_client.subrequests.send(blueprint, format=Format.json)
|
||||
result = json.loads(response["create-log#body{0}"]["body"])
|
||||
return result
|
||||
return response
|
||||
|
||||
def redirect_after_save(self, result):
|
||||
return self.redirect(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue