Files
scalesApp/backend/api/migrations/0006_scaleprotocol.py
T
gitea 4b6138f049 Add extra-data combinations, single measure flow, protocols and licensing
Four related backend features. They are committed together because they
interleave in api/views.py and api/serializers.py - one hunk holds the
combinations ViewSet, the licensing helpers and LicenseView - and
splitting by hunk would produce commits that do not import.

ExtraCombination records previously-used combinations of lookup
nomenclature values so an operator can refill the Additional Data fields
in one click. Deduplicated by a canonical order-independent hash, since
JSONField equality compares serialized text on SQLite and so depends on
key order.

Weighing replaces set_tare/set_gross with a single measure action that
assigns by weight - lighter becomes tare, heavier gross - because trucks
arrive both loaded and empty. A second, lighter reading moves the first
to gross carrying its own timestamp, user and manual fields, so
provenance follows the value rather than the slot. Manual entries record
who, when and why, gated on the previously unenforced can_measure and
can_manually_measure flags.

ScaleProtocol stores how to read each indicator, so a new scale type is
a configuration change rather than a new binary on every station PC.

Licensing is offline and node-locked: the server verifies an Ed25519
signature against a fingerprint of four hardware components, tolerating
one change, and counts concurrently connected stations. Sites are
air-gapped, so there is no activation server. A 14-day grace period
keeps an unlicensed or newly-invalid install working, because a licence
check must never stop a weighbridge without warning.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 18:57:29 +03:00

53 lines
1.7 KiB
Python

# Generated by Django 6.0.1 on 2026-09-17 16:01
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("api", "0005_grant_admin_permissions"),
]
operations = [
migrations.CreateModel(
name="ScaleProtocol",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("name", models.CharField(max_length=100, unique=True)),
(
"kind",
models.CharField(
choices=[
("fixed_column", "Fixed column"),
("simulator", "Simulator (ST/US)"),
("toledo_continuous", "Toledo Continuous"),
("sics", "Mettler-Toledo SICS"),
],
default="fixed_column",
max_length=20,
),
),
(
"poll_command",
models.CharField(blank=True, default="", max_length=20),
),
("poll_interval", models.FloatField(default=0.2)),
("config", models.JSONField(blank=True, default=dict)),
("is_builtin", models.BooleanField(default=False)),
("is_active", models.BooleanField(default=True)),
],
options={
"ordering": ["name"],
},
),
]