Add backdating support to egg harvest and sell forms
Both forms now have datetime pickers like the feed forms, allowing users to record events at past timestamps. Each form has a unique field_id (harvest_datetime, sell_datetime) to avoid conflicts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,26 @@ from animaltrack.services.products import ProductService, ValidationError
|
|||||||
from animaltrack.web.templates import render_page
|
from animaltrack.web.templates import render_page
|
||||||
from animaltrack.web.templates.eggs import eggs_page
|
from animaltrack.web.templates.eggs import eggs_page
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_ts_utc(form_value: str | None) -> int:
|
||||||
|
"""Parse ts_utc from form, defaulting to current time if empty or zero.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
form_value: The ts_utc value from form data.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Timestamp in milliseconds. Returns current time if form_value is
|
||||||
|
None, empty, or "0".
|
||||||
|
"""
|
||||||
|
if not form_value or form_value == "0":
|
||||||
|
return int(time.time() * 1000)
|
||||||
|
try:
|
||||||
|
ts = int(form_value)
|
||||||
|
return ts if ts > 0 else int(time.time() * 1000)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return int(time.time() * 1000)
|
||||||
|
|
||||||
|
|
||||||
# APIRouter for multi-file route organization
|
# APIRouter for multi-file route organization
|
||||||
ar = APIRouter()
|
ar = APIRouter()
|
||||||
|
|
||||||
@@ -147,8 +167,8 @@ async def product_collected(request: Request, session):
|
|||||||
request, locations, products, location_id, "Quantity must be at least 1"
|
request, locations, products, location_id, "Quantity must be at least 1"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get current timestamp
|
# Get timestamp - use provided or current (supports backdating)
|
||||||
ts_utc = int(time.time() * 1000)
|
ts_utc = _parse_ts_utc(form.get("ts_utc"))
|
||||||
|
|
||||||
# Resolve ducks at location
|
# Resolve ducks at location
|
||||||
resolved_ids = resolve_ducks_at_location(db, location_id, ts_utc)
|
resolved_ids = resolve_ducks_at_location(db, location_id, ts_utc)
|
||||||
@@ -276,8 +296,8 @@ async def product_sold(request: Request, session):
|
|||||||
request, locations, products, product_code, "Total price cannot be negative"
|
request, locations, products, product_code, "Total price cannot be negative"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Get current timestamp
|
# Get timestamp - use provided or current (supports backdating)
|
||||||
ts_utc = int(time.time() * 1000)
|
ts_utc = _parse_ts_utc(form.get("ts_utc"))
|
||||||
|
|
||||||
# Create product service
|
# Create product service
|
||||||
event_store = EventStore(db)
|
event_store = EventStore(db)
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ from monsterui.all import (
|
|||||||
from ulid import ULID
|
from ulid import ULID
|
||||||
|
|
||||||
from animaltrack.models.reference import Location, Product
|
from animaltrack.models.reference import Location, Product
|
||||||
|
from animaltrack.web.templates.actions import event_datetime_field
|
||||||
|
|
||||||
|
|
||||||
def eggs_page(
|
def eggs_page(
|
||||||
@@ -163,6 +164,8 @@ def harvest_form(
|
|||||||
name="notes",
|
name="notes",
|
||||||
placeholder="Optional notes",
|
placeholder="Optional notes",
|
||||||
),
|
),
|
||||||
|
# Event datetime picker (for backdating)
|
||||||
|
event_datetime_field("harvest_datetime"),
|
||||||
# Hidden nonce for idempotency
|
# Hidden nonce for idempotency
|
||||||
Hidden(name="nonce", value=str(ULID())),
|
Hidden(name="nonce", value=str(ULID())),
|
||||||
# Submit button
|
# Submit button
|
||||||
@@ -263,6 +266,8 @@ def sell_form(
|
|||||||
name="notes",
|
name="notes",
|
||||||
placeholder="Optional notes",
|
placeholder="Optional notes",
|
||||||
),
|
),
|
||||||
|
# Event datetime picker (for backdating)
|
||||||
|
event_datetime_field("sell_datetime"),
|
||||||
# Hidden nonce for idempotency
|
# Hidden nonce for idempotency
|
||||||
Hidden(name="nonce", value=str(ULID())),
|
Hidden(name="nonce", value=str(ULID())),
|
||||||
# Submit button
|
# Submit button
|
||||||
|
|||||||
Reference in New Issue
Block a user