Listings bulk actions: every ticked row counts as changed, and re-shortlisting resets the decision date #508
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
performance
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Postulo/postulo#508
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found on 2026-09-29 in a read-only review of postulo at
95348908d, comparing the three bulk views with the helper they share.Related to #134.
Checked again on 2026-10-01 against
mainat0a5cad587: still present. The code is now atjobs/models.py:1022-1039(JobPosting.shortlist,discard,restore); the other locations have not moved.bulk.changedpromises to say how many rows did change, and the applications bulk view keeps that promise. The listings bulk view does not: it counts every ticked row, and calls the model method on rows already in the target state, which overwrites their decision date.jobs/listing_views.py:183-193(ListingBulkView.post);jobs/models.py:1019-1036(JobPosting.shortlist,discard,restore); the rule it drifts from atcore/bulk.py:102-108andapplications/views.py:318-329(ApplicationBulkView._status, which skips rowschange_statusreports as unchanged).listing.shortlist()on all 40 and adds one tochangedeach time, so the message says "40 listings changed."shortlist()setsdecided_at = timezone.now()and saves unconditionally, so the 35 lose the date they were really shortlisted on and get a newupdated_at. Restore on listings that are already new and Discard on listings already discarded for the same reason behave the same way.bulk.changedexists to prevent, and the decision date — exposed by the API (api/schemas.py:648) and written into the export (core/export.py:185) — is rewritten for listings nobody changed. The two copies of "count only what changed" have drifted, and the next bulk view will copy whichever it finds first.shortlist,discardandrestorereturn whether they changed anything (no-op when the state, and for discard the reason, are already the target), aschange_statusdoes by returningNone; count only the rows that report a change inListingBulkView.post. The single-row views and the API (jobs/listing_views.py:245-254,api/routers/listings.py:228-243) then stop re-stamping as well.Done when
tests/test_listings_table.pyticks one new and one already-shortlisted listing, presses Shortlist, and finds "1 listing changed." and the shortlisted one'sdecided_atunchanged.