Spoolman leads CC2 Control's copies; new spools from the bridge
- Master data of CC2 Control's copies follows Spoolman (name, brand, colour, diameter, density, net, tare, price; not the material, which was fitted to the tray). - A loaded spool's rest in CC2 Control is set to Spoolman's via /api/spools/adjust once everything is booked (old copy after the roll printed in the other printer, weigh-in in Spoolman); the resulting correction is not booked back. - Copies of spools archived or deleted in Spoolman are deleted from CC2 Control when no tray holds them (library limit 128); an outage never counts as deleted. - A roll that ran out is archived in Spoolman (setting, default on); a scan of an archived spool maps nothing. - A roll scanned again with unchanged tag data and put back into its old slot (after printing in the other printer) is recognised. - Tag generator: "Neue Spule" creates spools in Spoolman from an existing or a new filament (and vendor), labelled vendor + id, then opens the tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GcEk5tkfFSYD6NTF66NkC
This commit is contained in:
1 parent
d03668e3c5
commit
b37cd64909
13 files changed
+873
-27
No files matched your search
+64
-2
@@ -52,6 +52,7 @@ class FakeCC2:
|
||||
self.log: list[dict] = [] # newest first, as CC2 Control lists it
|
||||
self.calls: list[tuple] = []
|
||||
self.fail = False
|
||||
self.clock = None # set by tests that need log times for adjust
|
||||
self._ids = (f"s{i:04d}" for i in itertools.count(1))
|
||||
|
||||
def _check(self):
|
||||
@@ -78,8 +79,11 @@ class FakeCC2:
|
||||
self.calls.append(("save", dict(fields)))
|
||||
if fields.get("id"):
|
||||
sp = next(s for s in self.library if s["id"] == fields["id"])
|
||||
if "archived" in fields:
|
||||
sp["archived"] = fields["archived"] in ("1", 1, True)
|
||||
for key, value in fields.items():
|
||||
if key == "archived":
|
||||
sp["archived"] = value in ("1", 1, True)
|
||||
elif key != "id":
|
||||
sp[key] = value
|
||||
return {"ok": True, "id": sp["id"]}
|
||||
sp = {"id": next(self._ids), "name": fields.get("name", ""), "brand": fields.get("brand", ""),
|
||||
"material": fields["material"], "color": fields["color"], "diameter": fields.get("diameter", 1.75),
|
||||
@@ -89,6 +93,18 @@ class FakeCC2:
|
||||
self.library.append(sp)
|
||||
return {"ok": True, "id": sp["id"]}
|
||||
|
||||
def adjust(self, cc2_id, remaining):
|
||||
self._check()
|
||||
self.calls.append(("adjust", cc2_id, remaining))
|
||||
self.weigh(cc2_id, remaining, self.clock() if self.clock else 0)
|
||||
return {"ok": True, "remaining": remaining}
|
||||
|
||||
def delete(self, cc2_id):
|
||||
self._check()
|
||||
self.calls.append(("delete", cc2_id))
|
||||
self.library = [s for s in self.library if s["id"] != cc2_id]
|
||||
return {"ok": True}
|
||||
|
||||
def assign(self, slot, spool_id):
|
||||
self._check()
|
||||
self.calls.append(("assign", slot, spool_id))
|
||||
@@ -173,6 +189,11 @@ class FakeSpoolman:
|
||||
self.calls.append(("extra", sid, dict(body["extra"])))
|
||||
if "location" in body:
|
||||
sp["location"] = body["location"]
|
||||
if "lot_nr" in body:
|
||||
sp["lot_nr"] = body["lot_nr"]
|
||||
if "archived" in body:
|
||||
self.calls.append(("archived", sid, body["archived"]))
|
||||
sp["archived"] = bool(body["archived"])
|
||||
for key, value in (body.get("extra") or {}).items():
|
||||
if value is None:
|
||||
sp["extra"].pop(key, None)
|
||||
@@ -184,6 +205,47 @@ class FakeSpoolman:
|
||||
self._check()
|
||||
return [{"key": k, **v} for k, v in self.field_defs.items()]
|
||||
|
||||
vendor_list: list | None = None
|
||||
filament_list: list | None = None
|
||||
|
||||
def vendors(self):
|
||||
self._check()
|
||||
if self.vendor_list is None:
|
||||
self.vendor_list = [{"id": 1, "name": "SUNLU"}]
|
||||
return copy.deepcopy(self.vendor_list)
|
||||
|
||||
def filaments(self):
|
||||
self._check()
|
||||
if self.filament_list is None:
|
||||
self.filament_list = [{"id": 1, "name": "PLA+ Black", "vendor": {"id": 1, "name": "SUNLU"}, "material": "PLA+",
|
||||
"color_hex": "000000", "density": 1.24, "diameter": 1.75, "weight": 1000.0}]
|
||||
return copy.deepcopy(self.filament_list)
|
||||
|
||||
def create_vendor(self, body):
|
||||
self._check()
|
||||
self.calls.append(("create_vendor", dict(body)))
|
||||
v = {"id": len(self.vendors()) + 1, **body}
|
||||
self.vendor_list.append(v)
|
||||
return v
|
||||
|
||||
def create_filament(self, body):
|
||||
self._check()
|
||||
self.calls.append(("create_filament", dict(body)))
|
||||
vendor = next(v for v in self.vendors() if v["id"] == body["vendor_id"])
|
||||
f = {"id": len(self.filaments()) + 1, "vendor": vendor, **body}
|
||||
self.filament_list.append(f)
|
||||
return f
|
||||
|
||||
def create_spool(self, body):
|
||||
self._check()
|
||||
self.calls.append(("create_spool", dict(body)))
|
||||
sid = max(self.db, default=0) + 1
|
||||
fil = next(f for f in self.filaments() if f["id"] == body["filament_id"])
|
||||
self.db[sid] = {"id": sid, "lot_nr": None, "remaining_weight": body.get("initial_weight") or fil.get("weight"),
|
||||
"initial_weight": body.get("initial_weight"), "used_weight": 0.0, "location": body.get("location", ""),
|
||||
"archived": False, "extra": {}, "filament": fil}
|
||||
return copy.deepcopy(self.db[sid])
|
||||
|
||||
def add_field(self, key, params):
|
||||
self._check()
|
||||
self.calls.append(("field", key))
|
||||
|
||||
Reference in new issue
Block a user