"""Reapplicant history — badge vs kept attempts. No database: the helpers decide whether a prior row counts as Reapplied and how a system-dropped attempt is labelled. """ from job.candidate.serializers import ( is_assigned_application, rejection_reason, serialize_application_history, serialize_application_history_item, ) from job.candidate.views import _is_current_application, _is_earlier_application def test_unassigned_inbox_is_not_a_reapplication(): row = { "source": "inbox", "job_post_id": None, "job_title": None, "status": "CLOSED", "attachment": True, "match_status": "matched", } assert is_assigned_application(row) is False assert rejection_reason(row) is None def test_assigned_inbox_is_a_reapplication(): row = {"source": "inbox", "job_post_id": "job-1", "job_title": "Engineer"} assert is_assigned_application(row) is True assert rejection_reason(row) is None def test_form_role_name_counts_without_job_post(): row = {"source": "form", "job_post_id": None, "job_title": "Data Analyst"} assert is_assigned_application(row) is True def test_unreadable_cv_is_wrong_format(): row = { "source": "inbox", "job_post_id": None, "attachment": True, "match_status": "no_text", "status": "CLOSED", } assert rejection_reason(row) == "wrong_format" item = serialize_application_history_item(row) assert item["status"] == "WRONG_FORMAT" assert item["rejection_reason"] == "wrong_format" def test_body_only_mail_is_wrong_format(): row = {"source": "inbox", "job_post_id": None, "attachment": False, "status": "CLOSED"} assert rejection_reason(row) == "wrong_format" def test_filtered_classifier_row_is_wrong_format(): row = {"source": "filtered", "job_post_id": None, "status": "WRONG_FORMAT"} assert rejection_reason(row) == "wrong_format" history = serialize_application_history("a@x.com", applications=[row]) assert history["is_reapplicant"] is False assert history["applications"][0]["status"] == "WRONG_FORMAT" def test_history_reapplicant_needs_an_assigned_job(): unassigned = {"source": "inbox", "job_post_id": None, "status": "CLOSED", "attachment": True} assigned = {"source": "inbox", "job_post_id": "job-1", "job_title": "Engineer", "status": "PENDING"} only_mail = serialize_application_history("a@x.com", applications=[unassigned]) assert only_mail["is_reapplicant"] is False assert len(only_mail["applications"]) == 1 both = serialize_application_history("a@x.com", applications=[unassigned, assigned]) assert both["is_reapplicant"] is True assert len(both["applications"]) == 2 def test_clicked_inbox_row_is_not_a_previous_application(): """List payloads use `source` for the To address, not 'inbox'.""" pk = "11111111-1111-1111-1111-111111111111" item = {"source": "inbox", "message_id": pk, "inbox_id": 9, "job_post_id": None} payload = { "id": pk, "email": "a@x.com", "source": "careers-rozee@example.com", "position": "Backend Engineer", } assert _is_current_application(item, payload) is True assert _is_current_application(item, {"id": "other", "source": "careers-rozee@example.com"}) is False def test_form_row_matches_without_a_sheet_field(): fid = "22222222-2222-2222-2222-222222222222" item = {"source": "form", "form_data_id": fid, "job_title": "Analyst"} assert _is_current_application(item, {"id": fid, "candidate_email": "a@x.com"}) is True def test_filtered_row_matches_graph_id_on_detail_payload(): item = {"source": "filtered", "message_id": "AAMkGraph", "upstream_id": "AAMkGraph"} payload = {"id": "11111111-1111-1111-1111-111111111111", "message_id": "AAMkGraph"} assert _is_current_application(item, payload) is True def test_later_mail_is_not_a_previous_application(): """12:52 is later than 12:51 — it is not a previous attempt of the 12:51 row.""" later = {"source": "inbox", "message_id": "b", "applied_at": "2026-09-07T07:52:00+00:00"} payload = {"id": "a", "received": "2026-09-07T07:51:00+00:00"} assert _is_current_application(later, payload) is False assert _is_earlier_application(later, payload) is False def test_earlier_mail_is_a_previous_application(): earlier = {"source": "inbox", "message_id": "a", "applied_at": "2026-09-07T07:51:00+00:00"} payload = {"id": "b", "received": "2026-09-07T07:52:00+00:00"} assert _is_earlier_application(earlier, payload) is True def test_undated_row_is_not_guessed_earlier(): item = {"source": "inbox", "message_id": "b", "applied_at": None} payload = {"id": "a", "received": "2026-09-07T07:51:00+00:00"} assert _is_earlier_application(item, payload) is False def test_history_item_keeps_user_id(): item = serialize_application_history_item({ "source": "manual", "user_id": "user-1", "manual_upload_candidate_id": "m-1", "job_post_id": "job-1", "job_title": "Analyst", }) assert item["user_id"] == "user-1"