feat: Pay Salary quick action on home dashboard (deep-link to modal)
Admin Quick Actions tile -> /payroll/?action=pay-salary; the payroll page auto-clicks the existing paySalaryBtn then strips the param. Reuses all existing Pay-Salary machinery; param inert server-side. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
56c10ab938
commit
9ab0c68243
@ -209,6 +209,13 @@
|
|||||||
<i class="fas fa-money-check-alt"></i>
|
<i class="fas fa-money-check-alt"></i>
|
||||||
<span>Run Payroll</span>
|
<span>Run Payroll</span>
|
||||||
</a>
|
</a>
|
||||||
|
{# === PAY SALARY — quick path: opens the Pay-Salary modal on /payroll/ === #}
|
||||||
|
{# Same fa-user-tie icon as the payroll dashboard's Pay Salary button so #}
|
||||||
|
{# users have one mental model for "salary = fa-user-tie". #}
|
||||||
|
<a href="{% url 'payroll_dashboard' %}?action=pay-salary" class="quick-action">
|
||||||
|
<i class="fas fa-user-tie"></i>
|
||||||
|
<span>Pay Salary</span>
|
||||||
|
</a>
|
||||||
<a href="{% url 'work_history' %}" class="quick-action">
|
<a href="{% url 'work_history' %}" class="quick-action">
|
||||||
<i class="fas fa-history"></i>
|
<i class="fas fa-history"></i>
|
||||||
<span>View History</span>
|
<span>View History</span>
|
||||||
|
|||||||
@ -2116,6 +2116,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// === Quick-action deep-link: /payroll/?action=pay-salary ===
|
||||||
|
// The home dashboard "Pay Salary" Quick Action links here with this
|
||||||
|
// param. Auto-click the existing Pay Salary button (which does the
|
||||||
|
// clean-slate + type=Salary + managers-only scoping + modal open),
|
||||||
|
// then strip the param so a manual refresh or Back doesn't re-pop
|
||||||
|
// the modal. Best-effort — never let a deep-link quirk block the page.
|
||||||
|
try {
|
||||||
|
var _qsAction = new URLSearchParams(window.location.search).get('action');
|
||||||
|
if (_qsAction === 'pay-salary' && paySalaryBtn) {
|
||||||
|
paySalaryBtn.click();
|
||||||
|
var _u = new URL(window.location.href);
|
||||||
|
_u.searchParams.delete('action');
|
||||||
|
window.history.replaceState({}, '', _u.pathname + _u.search + _u.hash);
|
||||||
|
}
|
||||||
|
} catch (e) { /* deep-link is best-effort; never block the page */ }
|
||||||
|
|
||||||
// When the modal is opened from the HEADER button (not quick-adjust,
|
// When the modal is opened from the HEADER button (not quick-adjust,
|
||||||
// not Pay-Salary), clear any pre-selected workers/project and reset
|
// not Pay-Salary), clear any pre-selected workers/project and reset
|
||||||
// the type to Bonus.
|
// the type to Bonus.
|
||||||
|
|||||||
@ -3307,6 +3307,37 @@ class WorkerListPayTypeFilterTests(TestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class PaySalaryQuickActionTests(TestCase):
|
||||||
|
"""Home dashboard 'Pay Salary' Quick Action: an admin sees a tile
|
||||||
|
that deep-links /payroll/?action=pay-salary; the param is inert
|
||||||
|
server-side (no view change). The auto-open click is client-side
|
||||||
|
JS, verified by manual checklist (not asserted here)."""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.admin = User.objects.create_user(
|
||||||
|
username='psqa_admin', password='pw',
|
||||||
|
is_staff=True, is_superuser=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.client.force_login(self.admin)
|
||||||
|
|
||||||
|
def test_home_has_pay_salary_quick_action(self):
|
||||||
|
resp = self.client.get('/')
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
# The tile links to the payroll dashboard with the deep-link param.
|
||||||
|
self.assertContains(resp, '?action=pay-salary')
|
||||||
|
# And is labelled "Pay Salary".
|
||||||
|
self.assertContains(resp, 'Pay Salary')
|
||||||
|
|
||||||
|
def test_payroll_dashboard_ignores_action_param(self):
|
||||||
|
# The param is purely a client-side signal; the view must not
|
||||||
|
# care about it — same 200 as a plain /payroll/ load.
|
||||||
|
resp = self.client.get('/payroll/?action=pay-salary')
|
||||||
|
self.assertEqual(resp.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
class WorkHistoryTeamFilterTests(TestCase):
|
class WorkHistoryTeamFilterTests(TestCase):
|
||||||
"""The /history/ page accepts ?team=<id> to narrow to logs tagged
|
"""The /history/ page accepts ?team=<id> to narrow to logs tagged
|
||||||
with that team, ?team=none for logs with no team set, and empty
|
with that team, ?team=none for logs with no team set, and empty
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user