|
|
user: when both tare and gross are filled out, net should be calculated and saved (at backend). doc_number should be generated and assigned to the vehicle record. how will be the document number generated, what is better, use the vehicle id or a generator?
|
|
|
Claude’s Plan
|
|
|
Plan: Auto-calculate net + assign doc_number when both tare and gross are set
|
|
|
Context
|
|
|
One vehicle record = one weighing trip. When both tare and gross are recorded, the backend should
|
|
|
automatically compute net = gross - tare, stamp net_date/net_user, and assign a unique
|
|
|
document number formatted as YYYY-NNNNNN (year + 6-digit sequential counter, resetting per year).
|
|
|
No frontend change is needed — the net and doc_number come back in the existing SSE broadcast.
|
|
|
|
|
|
Files to Modify
|
|
|
File Change
|
|
|
backend/api/models.py Add DocumentCounter model
|
|
|
backend/vehicles/models.py Add doc_number field to Vehicle
|
|
|
backend/api/serializers.py Add net, net_date, net_user_name, doc_number to VehicleSerializer
|
|
|
backend/api/views.py Update set_tare and set_gross to compute net + doc_number
|
|
|
new migration in api For DocumentCounter
|
|
|
new migration in vehicles For doc_number on Vehicle
|
|
|
Step 1 — Add DocumentCounter model (backend/api/models.py)
|
|
|
|
|
|
class DocumentCounter(models.Model):
|
|
|
year = models.IntegerField(unique=True)
|
|
|
last_number = models.IntegerField(default=0)
|
|
|
Add a helper function in the same file (or in views.py, but models.py keeps it reusable):
|
|
|
|
|
|
|
|
|
from django.db import transaction
|
|
|
|
|
|
def generate_doc_number(year):
|
|
|
with transaction.atomic():
|
|
|
counter, _ = DocumentCounter.objects.select_for_update().get_or_create(
|
|
|
year=year, defaults={'last_number': 0}
|
|
|
)
|
|
|
counter.last_number += 1
|
|
|
counter.save()
|
|
|
return f"{year}-{counter.last_number:06d}"
|
|
|
Step 2 — Add doc_number to Vehicle (backend/vehicles/models.py)
|
|
|
|
|
|
doc_number = models.CharField(max_length=20, null=True, blank=True, unique=True)
|
|
|
Place after the net_user field.
|
|
|
|
|
|
Step 3 — Update VehicleSerializer (backend/api/serializers.py)
|
|
|
Add to the VehicleSerializer:
|
|
|
|
|
|
|
|
|
net_user_name = serializers.CharField(source='net_user.username', read_only=True, default=None)
|
|
|
Add to fields list:
|
|
|
|
|
|
|
|
|
'net', 'net_date', 'net_user', 'net_user_name', 'doc_number'
|
|
|
Add to read_only_fields:
|
|
|
|
|
|
|
|
|
'net', 'net_date', 'net_user', 'net_user_name', 'doc_number'
|
|
|
Step 4 — Update set_tare and set_gross (backend/api/views.py)
|
|
|
Extract a helper to avoid duplication:
|
|
|
|
|
|
|
|
|
def _maybe_finalize(vehicle, user):
|
|
|
"""If both tare and gross are now set, compute net and assign doc_number."""
|
|
|
if vehicle.tare is not None and vehicle.gross is not None and vehicle.net is None:
|
|
|
vehicle.net = vehicle.gross - vehicle.tare
|
|
|
vehicle.net_date = timezone.now()
|
|
|
vehicle.net_user = user
|
|
|
vehicle.doc_number = generate_doc_number(timezone.now().year)
|
|
|
vehicle.save()
|
|
|
Call _maybe_finalize(vehicle, request.user) at the end of both set_tare and set_gross,
|
|
|
before the SSE broadcast and serializer response (so the response already contains net + doc_number).
|
|
|
|
|
|
Import generate_doc_number from api.models.
|
|
|
|
|
|
Step 5 — Migrations
|
|
|
|
|
|
python manage.py makemigrations api # DocumentCounter
|
|
|
python manage.py makemigrations vehicles # doc_number on Vehicle
|
|
|
python manage.py migrate
|
|
|
Verification
|
|
|
Create a vehicle with no tare/gross → net and doc_number are null
|
|
|
Set tare → net still null (only one weight set)
|
|
|
Set gross → net is calculated, net_date and net_user are set, doc_number is "2026-000001"
|
|
|
Second vehicle completes → doc_number is "2026-000002"
|
|
|
Race condition test (optional): two simultaneous requests → both get unique sequential numbers
|
|
|
Frontend SSE update reflects net and doc_number automatically (no frontend change needed) |