fix resid taeid accsess

This commit is contained in:
javad committed 2026-10-06 15:06:35 +03:30
1 parent b53a3e0c5c
commit 4f7486152c
4 files changed
+115 -10

No files matched your search

+15 -1
View File
@@ -26,7 +26,6 @@ def payment_case(settings,tmp_path):
for index in range(2):
user=User.objects.create_user(username=f'payment-e2e-reviewer-{index}',password=PASSWORD,account_type='STAFF')
StaffProfile.objects.create(user=user,display_name=f'تأییدکننده {index}')
user.user_permissions.add(Permission.objects.get(content_type__app_label='payments',codename='approve_paymentreceipt'))
reviewers.append(user)
policy=PaymentApprovalPolicy.objects.create(name='تأیید هر دو نفر')
policy.reviewers.add(*reviewers)
@@ -85,6 +84,21 @@ def test_form_errors_focus_and_full_copy(live_server,browser_page,payment_case):
expect(page.get_by_text('کپی شد',exact=True).or_(page.get_by_role('heading',name='متن را انتخاب و کپی کنید'))).to_be_visible()
def test_policy_senior_finalizes_without_extra_permissions(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
PaymentApprovalPolicy.objects.get().seniors.add(reviewers[0])
with browser_page() as page:
AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
PaymentsPage(page, live_server.url).send_receipt(account.pk, PNG)
receipt_id = page.url.rstrip('/').rsplit('/', 1)[-1]
page.get_by_role('button', name='خروج', exact=True).first.click()
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
PaymentsPage(page, live_server.url).approve(receipt_id, senior=True)
expect(page.get_by_text('تأیید شده', exact=True)).to_be_visible()
expect(page.get_by_role('button', name='ثبت تأیید من')).to_have_count(0)
expect(page.get_by_role('button', name='رد فیش')).to_have_count(0)
def test_amount_grouping_and_jalali_leap_calendar(live_server,browser_page,payment_case):
customer,account,reviewers=payment_case
with browser_page() as page:
+96 -3
View File
@@ -101,6 +101,68 @@ def test_senior_explicit_override_and_reason(case):
assert PaymentAuditEvent.objects.filter(action='SENIOR_APPROVE').exists()
@pytest.mark.parametrize('reviewer_count', [1, 2])
def test_policy_reviewers_can_approve_without_extra_permissions(case, client, reviewer_count):
case['policy'].reviewers.set([case['first'], case['second']][:reviewer_count])
for key in ['first', 'second']:
case[key].user_permissions.clear()
receipt = submit(case)
endpoint = reverse('staff_payments:decision', args=[receipt.public_id])
detail = reverse('staff_payments:receipt_detail', args=[receipt.public_id])
for index, key in enumerate(['first', 'second'][:reviewer_count]):
client.force_login(case[key])
page = client.get(detail)
assert page.context['can_approve']
assert not page.context['can_senior']
assert 'ثبت تأیید من' in page.content.decode()
assert 'رد فیش' in page.content.decode()
response = client.post(endpoint, {'version': 1, 'action': 'APPROVE'})
assert response.status_code == 302
receipt.refresh_from_db()
final = index == reviewer_count - 1
assert receipt.status == ('APPROVED' if final else 'PARTIAL')
assert NotificationJob.objects.filter(event_type='PAYMENT_RECEIPT_APPROVED').count() == int(final)
assert ReceiptDecision.objects.filter(cycle__revision__receipt=receipt).count() == reviewer_count
@pytest.mark.parametrize('also_required', [False, True])
def test_policy_senior_can_finalize_alone_without_extra_permissions(case, client, also_required):
case['senior'].user_permissions.clear()
if also_required:
case['policy'].reviewers.add(case['senior'])
receipt = submit(case)
client.force_login(case['senior'])
page = client.get(reverse('staff_payments:receipt_detail', args=[receipt.public_id]))
assert page.context['can_senior']
assert page.context['can_approve'] == also_required
assert 'تأیید نهایی ارشد' in page.content.decode()
endpoint = reverse('staff_payments:decision', args=[receipt.public_id])
client.post(endpoint, {'version': 1, 'action': 'SENIOR_APPROVE'})
assert not ReceiptDecision.objects.exists()
response = client.post(endpoint, {'version': 1, 'action': 'SENIOR_APPROVE', 'reason': 'تطبیق انجام شد'})
assert response.status_code == 302
receipt.refresh_from_db()
assert receipt.status == 'APPROVED'
assert ReceiptDecision.objects.get().user == case['senior']
assert NotificationJob.objects.filter(event_type='PAYMENT_RECEIPT_APPROVED').count() == 1
@pytest.mark.parametrize('key', ['first', 'senior'])
def test_policy_members_can_reject_without_extra_permissions(case, client, key):
case[key].user_permissions.clear()
receipt = submit(case)
client.force_login(case[key])
detail = client.get(reverse('staff_payments:receipt_detail', args=[receipt.public_id]))
assert 'رد فیش' in detail.content.decode()
response = client.post(reverse('staff_payments:decision', args=[receipt.public_id]),
{'version': 1, 'action': 'REJECT', 'reason': 'تصویر ناخوانا است'})
assert response.status_code == 302
receipt.refresh_from_db()
assert receipt.status == 'REJECTED'
assert ReceiptDecision.objects.get().action == 'REJECT'
assert not NotificationJob.objects.filter(event_type='PAYMENT_RECEIPT_APPROVED').exists()
@pytest.mark.parametrize('who',['customer','creator','outsider'])
def test_view_and_create_never_imply_approval(case,who):
receipt = submit(case)
@@ -108,6 +170,36 @@ def test_view_and_create_never_imply_approval(case,who):
services.decide_receipt(case[who],receipt.public_id,1,'APPROVE')
@pytest.mark.parametrize('action', ['APPROVE', 'SENIOR_APPROVE', 'REJECT'])
def test_django_permissions_without_assignment_do_not_allow_decisions(case, client, action):
grant(case['outsider'], 'approve_paymentreceipt')
grant(case['outsider'], 'senior_approve_paymentreceipt')
receipt = submit(case)
client.force_login(case['outsider'])
page = client.get(reverse('staff_payments:receipt_detail', args=[receipt.public_id]))
assert not page.context['can_approve'] and not page.context['can_senior']
response = client.post(reverse('staff_payments:decision', args=[receipt.public_id]),
{'version': 1, 'action': action, 'reason': 'بررسی انجام شد'})
assert response.status_code == 403
assert not ReceiptDecision.objects.exists()
@pytest.mark.parametrize('blocked_by', ['visibility', 'own_submission', 'inactive_user', 'inactive_profile'])
def test_policy_assignment_preserves_decision_restrictions(case, blocked_by):
receipt = submit(case)
if blocked_by == 'visibility':
PaymentAccessConfiguration.objects.update_or_create(pk=1, defaults={'open_view': False})
elif blocked_by == 'own_submission':
PaymentReceipt.objects.filter(pk=receipt.pk).update(submitted_by=case['first'])
elif blocked_by == 'inactive_user':
User.objects.filter(pk=case['first'].pk).update(is_active=False)
else:
StaffProfile.objects.filter(user=case['first']).update(is_active=False)
with pytest.raises(PermissionDenied):
services.decide_receipt(case['first'], receipt.public_id, 1, 'APPROVE')
assert not ReceiptDecision.objects.exists()
def test_rejection_ends_cycle_and_preserves_evidence(case):
receipt = submit(case)
services.decide_receipt(case['first'],receipt.public_id,1,'REJECT','تصویر پرداخت خوانا نیست')
@@ -341,7 +433,7 @@ def test_payment_posts_enforce_csrf_and_revoked_approval(case):
client.force_login(case['first'])
endpoint = reverse('staff_payments:decision',args=[receipt.public_id])
assert client.post(endpoint, {'version':1,'action':'APPROVE'}).status_code == 403
case['first'].user_permissions.clear()
StaffProfile.objects.filter(user=case['first']).update(is_active=False)
actor = User.objects.get(pk=case['first'].pk)
with pytest.raises(PermissionDenied):
services.decide_receipt(actor,receipt.public_id,1,'APPROVE')
@@ -427,11 +519,12 @@ def test_financial_sms_model_clean_supplies_admin_readonly_tags(case):
template.full_clean()
def test_cached_user_cannot_vote_after_permission_revocation(case):
def test_cached_user_cannot_vote_after_staff_deactivation(case):
receipt=submit(case)
actor=case['first']
assert actor.has_perm('payments.approve_paymentreceipt')
actor.user_permissions.clear()
assert actor.staff_profile.is_active
StaffProfile.objects.filter(user=actor).update(is_active=False)
with pytest.raises(PermissionDenied):
services.decide_receipt(actor,receipt.public_id,1,'APPROVE')
assert not ReceiptDecision.objects.exists()