Compare commits
No commits in common. "e27dad573b84fe262a8267ca498412476d28f1af" and "a5b699a52ab7f92cae7ef87e2d5eff62d547880c" have entirely different histories.
e27dad573b
...
a5b699a52a
7 changed files with 19 additions and 167 deletions
|
|
@ -5,13 +5,6 @@ All notable changes to WuttaFarm will be documented in this file.
|
|||
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## v0.11.3 (2026-05-04)
|
||||
|
||||
### Fix
|
||||
|
||||
- set material types when creating new log w/ material quantity
|
||||
- split numerator/denominator for quantity values
|
||||
|
||||
## v0.11.2 (2026-03-21)
|
||||
|
||||
### Fix
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ include:
|
|||
:maxdepth: 2
|
||||
:caption: Documentation:
|
||||
|
||||
narr/intro
|
||||
narr/install
|
||||
narr/auth
|
||||
narr/features
|
||||
|
|
|
|||
|
|
@ -1,123 +0,0 @@
|
|||
|
||||
==============
|
||||
Introduction
|
||||
==============
|
||||
|
||||
This page hopefully conveys the what and why of WuttaFarm as a project.
|
||||
|
||||
WuttaFarm can serve as a "supplement" or "alternative" to `farmOS
|
||||
<https://farmos.org>`_, depending on your needs. It has 3 distinct
|
||||
"modes" of operation:
|
||||
|
||||
* :ref:`wrapper (API only) <wrapper-mode>`
|
||||
* :ref:`mirror (2-way sync) <mirror-mode>`
|
||||
* :ref:`standalone <standalone-mode>`
|
||||
|
||||
|
||||
Rationale
|
||||
---------
|
||||
|
||||
This project exists primarily to scratch a personal itch, but the hope
|
||||
of course is that others will find it useful also. This is partly why
|
||||
the app has different integration modes.
|
||||
|
||||
Realistically this is not (yet?) meant to be a "finished" app per se.
|
||||
In that sense it is akin to farmOS itself, i.e. "part app, part
|
||||
framework" which can be extended where needed.
|
||||
|
||||
It purposefully does not try to re-invent every wheel provided by
|
||||
farmOS. But it does re-invent "certain types" of wheels, to some
|
||||
degree, depending on which mode is used.
|
||||
|
||||
It should also be mentioned, the 3 "modes" are essentially just
|
||||
abstractions for sake of convenience. The framework allows one to
|
||||
customize however you want regardless of the "mode" in effect.
|
||||
|
||||
The target audience I suppose, is folks like me who prefer Python over
|
||||
PHP, and can customize away without having to touch Drupal.
|
||||
|
||||
|
||||
.. _wrapper-mode:
|
||||
|
||||
Wrapper Mode (API only)
|
||||
-----------------------
|
||||
|
||||
This is the default integration mode for the app. In wrapper mode,
|
||||
WuttaFarm UI will only expose views which display/modify farmOS data
|
||||
*directly* via its JSONAPI. The app will not expose any views which
|
||||
operate on its "native" tables (for assets, logs etc.).
|
||||
|
||||
Any data model extensions needed must of course be managed on the
|
||||
farmOS side, since the native tables are not used for this mode.
|
||||
|
||||
This mode is simplest (for farmOS integration) since every user action
|
||||
goes immeditely through the API. There is no "sync" or caching
|
||||
involved.
|
||||
|
||||
There is one known issue with this mode, and it's kind of a bummer:
|
||||
|
||||
When viewing the "list" page for any record type (e.g. Animal Assets),
|
||||
due to a quirk with the JSONAPI, you can only see the "first 50"
|
||||
results in the listing. However you can still filter/sort the
|
||||
records, to hopefully find what you need. And you can still view
|
||||
*any* record if you have its URL (which you can normally figure out
|
||||
from the farmOS UUID value).
|
||||
|
||||
|
||||
.. _mirror-mode:
|
||||
|
||||
Mirror Mode (2-way sync)
|
||||
------------------------
|
||||
|
||||
This mode exposes the native table views in addition to direct API
|
||||
views. It's sort of a combination of the wrapper and standalone
|
||||
modes, with an extra daemon process to handle some of the sync tasks.
|
||||
|
||||
(It's also the most complex mode to setup; more "moving parts" which
|
||||
means potentially more to go wrong and require troubleshooting.)
|
||||
|
||||
Again this depends on your actual use case, but a "complete" setup for
|
||||
this mode would mean:
|
||||
|
||||
* changes made in WuttaFarm are synced to farmOS via JSONAPI
|
||||
* changes made in farmOS are synced to WuttaFarm via webhook+daemon
|
||||
|
||||
The latter includes changes made via the farmOS proper web app, and/or
|
||||
changes made via the "direct API" views within WuttaFarm (or anything
|
||||
else that invokes the farmOS API). This requires the extra daemon
|
||||
process (running alongside the WuttaFarm web app process), as well as
|
||||
the `webhooks module
|
||||
<https://farmos.discourse.group/t/using-the-webhooks-module/2490>`_ on
|
||||
the farmOS side.
|
||||
|
||||
It's possible to extend the data model on the WuttaFarm side with or
|
||||
without doing so on the farmOS side, and vice versa. Although
|
||||
regardless you may have to take both into consideration for your
|
||||
overall sync needs.
|
||||
|
||||
There is support for "full" data import/export between systems in both
|
||||
directions, WuttaFarm <=> farmOS. Limited of course by the common
|
||||
schema they share etc. This can be leveraged easily to include
|
||||
nightly "data diff" checks, ensuring all stays in sync.
|
||||
|
||||
|
||||
|
||||
.. _standalone-mode:
|
||||
|
||||
Standalone Mode
|
||||
---------------
|
||||
|
||||
This mode exposes *only* the native table views, and none of the
|
||||
"direct API" views. This requires no farmOS at all.
|
||||
|
||||
This lets you customize the data model as needed, using SQLAlchemy and
|
||||
Alembic, as does the mirror mode. However no "sync" is required so
|
||||
you don't have to consider the farmOS data model.
|
||||
|
||||
While the wrapper mode is simplest for farmOS integration, this
|
||||
standalone mode is even simpler, technically speaking. It should work
|
||||
well if you just need the basic record-keeping aspects.
|
||||
|
||||
The main downside with this mode is there is not (yet?) any
|
||||
mapping/geometry support, nor is there support for image/file
|
||||
attachments.
|
||||
|
|
@ -5,7 +5,7 @@ build-backend = "hatchling.build"
|
|||
|
||||
[project]
|
||||
name = "WuttaFarm"
|
||||
version = "0.11.3"
|
||||
version = "0.11.2"
|
||||
description = "Web app to integrate with and extend farmOS"
|
||||
readme = "README.md"
|
||||
authors = [
|
||||
|
|
|
|||
|
|
@ -138,11 +138,6 @@ class WuttaFarmMenuHandler(base.MenuHandler):
|
|||
"route": "land_types",
|
||||
"perm": "land_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Material Types",
|
||||
"route": "material_types",
|
||||
"perm": "material_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Plant Types",
|
||||
"route": "plant_types",
|
||||
|
|
@ -223,6 +218,11 @@ class WuttaFarmMenuHandler(base.MenuHandler):
|
|||
"route": "log_types",
|
||||
"perm": "log_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Material Types",
|
||||
"route": "material_types",
|
||||
"perm": "material_types.list",
|
||||
},
|
||||
{
|
||||
"title": "Measures",
|
||||
"route": "measures",
|
||||
|
|
|
|||
|
|
@ -847,18 +847,12 @@
|
|||
}
|
||||
|
||||
const measureMap = {}
|
||||
for (const m of this.measures) {
|
||||
for (let m of this.measures) {
|
||||
measureMap[m.drupal_id] = m.name
|
||||
}
|
||||
|
||||
const quantityTypeMap = {}
|
||||
for (const qt of this.quantityTypes) {
|
||||
quantityTypeMap[qt.drupal_id] = qt.name
|
||||
}
|
||||
|
||||
return {
|
||||
measureMap,
|
||||
quantityTypeMap,
|
||||
quantityType: this.defaultQuantityType,
|
||||
editShowDialog: false,
|
||||
editNew: true,
|
||||
|
|
@ -899,7 +893,8 @@
|
|||
|
||||
this.newQuantity.quantity_type = {
|
||||
drupal_id: this.quantityType,
|
||||
name: this.quantityTypeMap[this.quantityType],
|
||||
## TODO: add support for other quantity types
|
||||
name: "Standard",
|
||||
}
|
||||
|
||||
this.newQuantity.measure = null
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
Base views for Logs
|
||||
"""
|
||||
|
||||
import decimal
|
||||
import time
|
||||
from collections import OrderedDict
|
||||
|
||||
import colander
|
||||
|
|
@ -400,16 +398,13 @@ class LogMasterView(WuttaFarmMasterView):
|
|||
units = session.get(model.Unit, new_qty["units"]["uuid"])
|
||||
assert units
|
||||
if new_qty["uuid"].startswith("new_"):
|
||||
num, denom = decimal.Decimal(new_qty["value"]).as_integer_ratio()
|
||||
qty = self.app.make_true_quantity(
|
||||
new_qty["quantity_type"]["drupal_id"],
|
||||
measure_id=new_qty["measure"],
|
||||
value_numerator=num,
|
||||
value_denominator=denom,
|
||||
value_numerator=int(new_qty["value"]),
|
||||
value_denominator=1,
|
||||
units=units,
|
||||
)
|
||||
if qty.quantity_type_id == "material":
|
||||
self.set_material_types(qty, new_qty["material_types"])
|
||||
# nb. must ensure "typed" quantity record persists!
|
||||
session.add(qty)
|
||||
# but must add "generic" quantity record to log
|
||||
|
|
@ -446,19 +441,12 @@ class LogMasterView(WuttaFarmMasterView):
|
|||
if old_mtype.uuid.hex not in desired:
|
||||
quantity.material_types.remove(old_mtype)
|
||||
|
||||
def auto_sync_to_farmos(self, client, uuid):
|
||||
def auto_sync_to_farmos(self, client, log):
|
||||
model = self.app.model
|
||||
model_class = self.get_model_class()
|
||||
session = self.Session()
|
||||
|
||||
with self.app.short_session(commit=True) as session:
|
||||
if user := session.query(model.User).filter_by(username="farmos").first():
|
||||
session.info["continuum_user_id"] = user.uuid
|
||||
|
||||
log = None
|
||||
while not log:
|
||||
log = session.get(model_class, uuid)
|
||||
if not log:
|
||||
time.sleep(0.1)
|
||||
# nb. ensure quantities have uuid keys
|
||||
session.flush()
|
||||
|
||||
for qty in log.quantities:
|
||||
qty = self.app.get_true_quantity(qty)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue