diff --git a/crudkit/core/service.py b/crudkit/core/service.py index 366900a..fd8c953 100644 --- a/crudkit/core/service.py +++ b/crudkit/core/service.py @@ -649,15 +649,16 @@ class CRUDService(Generic[T]): return rows - def create(self, data: dict, actor=None) -> T: + def create(self, data: dict, actor=None, *, commit: bool = True) -> T: session = self.session obj = self.model(**data) session.add(obj) - session.commit() - self._log_version("create", obj, actor) + if commit: + session.commit() + self._log_version("create", obj, actor, commit=commit) return obj - def update(self, id: int, data: dict, actor=None) -> T: + def update(self, id: int, data: dict, actor=None, *, commit: bool = True) -> T: session = self.session obj = session.get(self.model, id) if not obj: @@ -695,7 +696,8 @@ class CRUDService(Generic[T]): return obj # Commit atomically - session.commit() + if commit: + session.commit() # AFTER snapshot for audit after = obj.as_dict() @@ -712,10 +714,10 @@ class CRUDService(Generic[T]): return obj # Log both what we *intended* and what *actually* happened - self._log_version("update", obj, actor, metadata={"diff": actual, "patch": patch}) + self._log_version("update", obj, actor, metadata={"diff": actual, "patch": patch}, commit=commit) return obj - def delete(self, id: int, hard: bool = False, actor = None): + def delete(self, id: int, hard: bool = False, actor = None, *, commit: bool = True): session = self.session obj = session.get(self.model, id) if not obj: @@ -725,11 +727,12 @@ class CRUDService(Generic[T]): else: soft = cast(_SoftDeletable, obj) soft.is_deleted = True - session.commit() - self._log_version("delete", obj, actor) + if commit: + session.commit() + self._log_version("delete", obj, actor, commit=commit) return obj - def _log_version(self, change_type: str, obj: T, actor=None, metadata: dict | None = None): + def _log_version(self, change_type: str, obj: T, actor=None, metadata: dict | None = None, *, commit: bool = True): session = self.session try: snapshot = {} @@ -747,7 +750,8 @@ class CRUDService(Generic[T]): meta=to_jsonable(metadata) if metadata else None, ) session.add(version) - session.commit() + if commit: + session.commit() except Exception as e: - log.warning(f"Version logging failed for {self.model.__name__} id={getattr(obj, "id", "?")}: {str(e)}") + log.warning(f"Version logging failed for {self.model.__name__} id={getattr(obj, 'id', '?')}: {str(e)}") session.rollback() diff --git a/inventory/routes/entry.py b/inventory/routes/entry.py index 363f361..aa8bad4 100644 --- a/inventory/routes/entry.py +++ b/inventory/routes/entry.py @@ -9,6 +9,28 @@ from crudkit.core import normalize_payload bp_entry = Blueprint("entry", __name__) +def _apply_worklog_updates(worklog, updates, delete_ids): + note_cls = type(worklog).updates.property.mapper.class_ + note_svc = crudkit.crud.get_service(note_cls) + sess = note_svc.session + + existing = {u.id: u for u in worklog.updates if not getattr(u, "is_deleted", False)} + + for item in updates: + uid = item.get("id") + content = (item.get("content") or "").strip() + if not content and not uid: + continue + if uid: + # per-note version log preserved, but commit deferred. + note_svc.update(uid, {"content": content}, actor="bulk_child_update", commit=False) + else: + note_svc.create({"work_log_id": worklog.id, "content": content}, actor="bulk_child_create", commit=False) + + for uid in delete_ids: + if uid in existing: + note_svc.delete(uid, actor="bulk_child_delete", commit=False) + def init_entry_routes(app): @bp_entry.get("/entry//") @@ -168,6 +190,9 @@ def init_entry_routes(app): cls = crudkit.crud.get_model(model) payload = normalize_payload(request.get_json(), cls) + updates = payload.pop("updates", None) or [] + delete_ids = payload.pop("delete_update_ids", None) or [] + params = {} if model == "inventory": pass @@ -191,16 +216,25 @@ def init_entry_routes(app): "start_time", "end_time", "complete", + "updates", ] } else: raise TypeError("Invalid model.") service = crudkit.crud.get_service(cls) - service.update(id, data=payload, actor="update_entry") + sess = service.session + + obj = service.update(id, data=payload, actor="update_entry", commit=False) + + if model == "worklog" and (updates or delete_ids): + _apply_worklog_updates(obj, updates, delete_ids) + + sess.commit() return {"status": "success", "payload": payload} except Exception as e: + print(e) return {"status": "failure", "error": str(e)} app.register_blueprint(bp_entry) diff --git a/inventory/templates/submit_button.html b/inventory/templates/submit_button.html index c31081e..2d569b0 100644 --- a/inventory/templates/submit_button.html +++ b/inventory/templates/submit_button.html @@ -1,9 +1,13 @@ \ No newline at end of file diff --git a/inventory/templates/update_list.html b/inventory/templates/update_list.html index 6062dbd..f3eb929 100644 --- a/inventory/templates/update_list.html +++ b/inventory/templates/update_list.html @@ -1,106 +1,125 @@ {% set items = (field.template_ctx.instance.updates or []) %} + +