Konrad du Plessis 4c3e90f2a7 fix(adjustments): bulk-delete cascades through Loan + Overtime (critical)
Code-review found a data-integrity bug: the bulk-delete endpoint
bypassed the cascade logic that single-row delete_adjustment does
for 'New Loan', 'Advance Payment', and 'Overtime' types.

Without cascade, bulk-deleting a 'New Loan' adjustment would:
  - Delete the PayrollAdjustment row
  - LEAVE the linked Loan row orphaned in the DB (still shown in
    loan reports, still affecting remaining_balance queries)
  - LEAVE any scheduled unpaid Loan Repayment adjustments pointing
    at the orphaned Loan (they would silently deduct from the
    worker's next pay with no visible parent)

Bulk-deleting an 'Overtime' adjustment would leave the worker
stuck in work_log.priced_workers, making price_overtime() treat
them as already-priced even though the money is gone.

Fix: extracted _delete_adjustment_with_cascade(adj) helper that
captures the exact rules from the existing delete_adjustment view
— returns (ok, reason) so both callers can translate the outcome
into their own response shape. Both views now delegate to it.

bulk_delete_adjustments now loops over the selected rows, calls
the helper per-row, and returns JSON including skipped_reasons
(e.g. {'has_paid_repayments': 1} when a Loan with paid repayments
was refused). Also hardened the id-coercion to int so a garbled
POST payload can't crash the queryset with a ValueError.

Two new tests:
  - test_bulk_delete_cascades_new_loan — loan row + unpaid repayment
    must also be deleted
  - test_bulk_delete_skips_loan_with_paid_repayments — refuses to
    delete the loan but still processes other rows in the batch

64/64 tests pass (was 62). No API surface change visible to a user
who only uses the happy path — but the audit trail on Loans is
now safe even under bulk delete.
2026-04-23 19:06:54 +02:00
..
2026-02-22 12:14:54 +00:00
2026-04-22 00:19:15 +02:00
2026-02-22 12:14:54 +00:00
2026-02-22 12:14:54 +00:00
2026-04-22 00:19:15 +02:00
2026-04-22 00:19:15 +02:00