ux(labels): shorter adjustment type labels (display-only rename)

Path A rename - DB values untouched, only TYPE_CHOICES display
labels change:
  'New Loan'          -> shown as 'Loan'
  'Advance Payment'   -> shown as 'Advance'
  'Advance Repayment' -> shown as 'Advance Repaid'

Templates that render the type as visible text switched from
{{ adj.type }} to {{ adj.get_type_display }}. Data attributes and
CSS class slugs keep the raw DB value (identifiers, not labels).

Zero data migration. Zero changes to ADDITIVE_TYPES / DEDUCTIVE_TYPES
constants, hardcoded string comparisons, CSS class names, test
fixtures, or any other code that references the canonical DB value.
Every historic PayrollAdjustment row keeps type='New Loan' /
'Advance Payment' / 'Advance Repayment' as stored.

Django's makemigrations generated a no-op AlterField migration to
record the choices-metadata change.

Tests: 69/69.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Konrad du Plessis 2026-04-24 09:49:26 +02:00
parent e51a2f6d1d
commit c1d9014fe1
5 changed files with 36 additions and 11 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 5.2.7 on 2026-04-24 07:45
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0011_worker_tax_number'),
]
operations = [
migrations.AlterField(
model_name='payrolladjustment',
name='type',
field=models.CharField(choices=[('Bonus', 'Bonus'), ('Overtime', 'Overtime'), ('Deduction', 'Deduction'), ('Loan Repayment', 'Loan Repayment'), ('New Loan', 'Loan'), ('Advance Payment', 'Advance'), ('Advance Repayment', 'Advance Repaid')], max_length=50),
),
]

View File

@ -187,14 +187,21 @@ class Loan(models.Model):
return f"{self.worker.name} - {label} - {self.date}"
class PayrollAdjustment(models.Model):
# === PayrollAdjustment TYPE_CHOICES - canonical DB value | display label ===
# Path A rename (24 Apr 2026): DB values are PRESERVED as-is. Only the
# second tuple element (the human label) changes for three types, so
# users see shorter labels in tables while every historic row, formula,
# constant, test fixture, CSS class, and data-attribute KEEP WORKING
# UNCHANGED because they all key off the DB value on the left.
# See CLAUDE.md "UI-vs-DB naming drift" section for the full rule.
TYPE_CHOICES = [
('Bonus', 'Bonus'),
('Overtime', 'Overtime'),
('Deduction', 'Deduction'),
('Loan Repayment', 'Loan Repayment'),
('New Loan', 'New Loan'),
('Advance Payment', 'Advance Payment'),
('Advance Repayment', 'Advance Repayment'),
('Bonus', 'Bonus'),
('Overtime', 'Overtime'),
('Deduction', 'Deduction'),
('Loan Repayment', 'Loan Repayment'),
('New Loan', 'Loan'),
('Advance Payment', 'Advance'),
('Advance Repayment', 'Advance Repaid'),
]
worker = models.ForeignKey(Worker, on_delete=models.CASCADE, related_name='adjustments')

View File

@ -34,7 +34,7 @@ Row actions differ by paid status:
</td>
{# --- Type badge (colour comes from the .badge-type-<slug> CSS class) --- #}
<td><span class="badge-type-{{ adj.type|type_slug }}">{{ adj.type }}</span></td>
<td><span class="badge-type-{{ adj.type|type_slug }}">{{ adj.get_type_display }}</span></td>
{# --- Amount (sign reflects additive vs deductive) --- #}
<td class="text-end" style="font-variant-numeric: tabular-nums;">

View File

@ -367,7 +367,7 @@
data-adj-project="{{ adj.project_id|default:'' }}"
data-adj-worker="{{ adj.worker.name }}">
{% if adj.type == 'Bonus' or adj.type == 'Overtime' or adj.type == 'New Loan' or adj.type == 'Advance Payment' %}+{% else %}-{% endif %}R{{ adj.amount|floatformat:2 }}
{{ adj.type }}
{{ adj.get_type_display }}
{% if adj.project %}({{ adj.project.name }}){% endif %}
</span>
{% endfor %}
@ -451,7 +451,7 @@
<td class="align-middle d-none d-lg-table-cell">
{% for adj in record.adjustments.all %}
<span class="badge {% if adj.type == 'Bonus' or adj.type == 'Overtime' or adj.type == 'Loan Repayment' or adj.type == 'Advance Repayment' %}bg-success{% elif adj.type == 'New Loan' or adj.type == 'Advance Payment' %}bg-warning{% else %}bg-danger{% endif %} me-1">
{{ adj.type }}: R {{ adj.amount|floatformat:2 }}
{{ adj.get_type_display }}: R {{ adj.amount|floatformat:2 }}
</span>
{% empty %}
<span class="text-muted">-</span>

View File

@ -128,7 +128,7 @@
<tbody>
{% for adj in adjustments %}
<tr>
<td>{{ adj.type }}</td>
<td>{{ adj.get_type_display }}</td>
<td><a href="{% url 'worker_detail' adj.worker.id %}" class="text-decoration-none">{{ adj.worker.name }}</a></td>
<td class="text-end">R {{ adj.amount|money }}</td>
<td>