fix(campaigns): defer Jira ticket creation to start_date, gate recurring campaigns behind manager approval
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
Aegis CI / lint-and-test (push) Has been cancelled
Snyk Security Scan / Python vulnerabilities (backend) (push) Has been cancelled
Snyk Security Scan / npm vulnerabilities (frontend) (push) Has been cancelled
Snyk Security Scan / Docker image vulnerabilities (backend) (push) Has been cancelled
- Approve endpoint now only creates Jira tickets immediately when start_date is now/past; a new periodic job (every 15 min) catches campaigns whose scheduled start_date has since arrived. - Recurring campaign clones now go to pending_approval instead of active, routing through the same manager-approval gate as any other campaign; managers are notified instead of red_tech. - Fix UTC conversion for the campaign approval start_date input and extract shared isoToDatetimeLocal/datetimeLocalToIso helpers.
This commit is contained in:
@@ -45,7 +45,7 @@ def test_manager_can_approve_and_sets_start_date(api, db, red_lead_user, red_lea
|
||||
"post",
|
||||
f"/api/v1/campaigns/{campaign.id}/approve",
|
||||
manager_headers,
|
||||
json={"start_date": "2026-09-01T00:00:00"},
|
||||
json={"start_date": "2020-01-01T00:00:00"},
|
||||
)
|
||||
assert resp.status_code == 200
|
||||
body = resp.json()
|
||||
@@ -53,10 +53,13 @@ def test_manager_can_approve_and_sets_start_date(api, db, red_lead_user, red_lea
|
||||
assert body["start_date"] is not None
|
||||
|
||||
|
||||
def test_manager_approval_creates_jira_tickets(api, db, red_lead_user, red_lead_headers, manager_headers):
|
||||
def test_manager_approval_creates_jira_tickets_when_start_date_is_due(
|
||||
api, db, red_lead_user, red_lead_headers, manager_headers
|
||||
):
|
||||
"""The normal manager-approval path must create Jira tickets too, not just
|
||||
the admin-only emergency /activate override — this was the Block 1 gap:
|
||||
campaigns approved through the standard flow never got a Jira ticket."""
|
||||
campaigns approved through the standard flow never got a Jira ticket.
|
||||
Uses a past start_date so ticket creation is due immediately."""
|
||||
campaign = _make_draft_campaign(db, red_lead_user.id)
|
||||
api("post", f"/api/v1/campaigns/{campaign.id}/submit", red_lead_headers)
|
||||
|
||||
@@ -68,7 +71,7 @@ def test_manager_approval_creates_jira_tickets(api, db, red_lead_user, red_lead_
|
||||
"post",
|
||||
f"/api/v1/campaigns/{campaign.id}/approve",
|
||||
manager_headers,
|
||||
json={"start_date": "2026-09-01T00:00:00"},
|
||||
json={"start_date": "2020-01-01T00:00:00"},
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
@@ -77,6 +80,29 @@ def test_manager_approval_creates_jira_tickets(api, db, red_lead_user, red_lead_
|
||||
mock_create_test.assert_called_once()
|
||||
|
||||
|
||||
def test_manager_approval_skips_jira_tickets_when_start_date_is_future(
|
||||
api, db, red_lead_user, red_lead_headers, manager_headers
|
||||
):
|
||||
"""A campaign scheduled to start in the future must not get its Jira
|
||||
tickets created at approval time — that must wait for the periodic
|
||||
due-campaign sync job, once the scheduled start_date actually arrives."""
|
||||
campaign = _make_draft_campaign(db, red_lead_user.id)
|
||||
api("post", f"/api/v1/campaigns/{campaign.id}/submit", red_lead_headers)
|
||||
|
||||
with patch("app.services.jira_service.get_campaign_jira_key", return_value=None) as mock_get_key, \
|
||||
patch("app.services.jira_service.auto_create_campaign_issue", return_value="PT-100") as mock_create_campaign:
|
||||
resp = api(
|
||||
"post",
|
||||
f"/api/v1/campaigns/{campaign.id}/approve",
|
||||
manager_headers,
|
||||
json={"start_date": "2099-01-01T00:00:00"},
|
||||
)
|
||||
|
||||
assert resp.status_code == 200
|
||||
mock_get_key.assert_not_called()
|
||||
mock_create_campaign.assert_not_called()
|
||||
|
||||
|
||||
def test_lead_cannot_approve(api, db, red_lead_user, red_lead_headers):
|
||||
campaign = _make_draft_campaign(db, red_lead_user.id)
|
||||
api("post", f"/api/v1/campaigns/{campaign.id}/submit", red_lead_headers)
|
||||
|
||||
Reference in New Issue
Block a user