fix payment

This commit is contained in:
javad committed 2026-10-07 13:39:29 +03:30
1 parent 4f7486152c
commit bb3ddd1610
47 files changed
+2137 -51

No files matched your search

+94 -5
View File
@@ -25,6 +25,51 @@ def upload():
return SimpleUploadedFile('receipt.png', PNG, content_type='image/png')
@pytest.mark.parametrize('staff', [False, True])
def test_receipt_upload_json_success_keeps_flash_and_deduplicates(case, client, staff):
client.force_login(case['creator'] if staff else case['customer'])
endpoint = reverse('staff_payments:receipt_new', args=[case['customer'].public_id]) if staff else reverse('payments:receipt_new')
values = data(case)
first = client.post(endpoint, {**values, 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert first.status_code == 200
receipt = PaymentReceipt.objects.get(customer=case['customer'])
expected = reverse('staff_payments:receipt_detail' if staff else 'payments:receipt_detail', args=[receipt.public_id])
assert first.json() == {'redirect_url': expected}
repeated = client.post(endpoint, {**values, 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert repeated.json() == first.json()
assert PaymentReceipt.objects.filter(customer=case['customer']).count() == 1
assert 'فیش ثبت شد و در انتظار بررسی است.' in client.get(expected).content.decode()
def test_receipt_upload_json_field_and_service_errors(case, client, monkeypatch):
client.force_login(case['customer'])
endpoint = reverse('payments:receipt_new')
invalid = client.post(endpoint, {**data(case), 'paid_amount': '0', 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert invalid.status_code == 422
assert invalid.json()['errors']['paid_amount'][0]['message']
def unavailable(*args, **kwargs):
raise ValidationError('اعلامیه دیگر قابل پرداخت نیست.')
monkeypatch.setattr(services, 'submit_receipt', unavailable)
response = client.post(endpoint, {**data(case), 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert response.status_code == 422
assert response.json()['errors']['__all__'][0]['message'] == 'اعلامیه دیگر قابل پرداخت نیست.'
assert not PaymentReceipt.objects.filter(customer=case['customer']).exists()
def test_receipt_revision_upload_json_errors_and_success(case, client):
receipt = submit(case)
services.decide_receipt(case['first'], receipt.public_id, 1, 'REJECT', 'تصویر خوانا نیست')
client.force_login(case['customer'])
endpoint = reverse('payments:receipt_revise', args=[receipt.public_id])
stale = client.post(endpoint, {**data(case), 'version': '0', 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert stale.status_code == 422 and stale.json()['errors']['__all__']
valid = client.post(endpoint, {**data(case), 'version': '1', 'receipt_image': upload()}, HTTP_ACCEPT='application/json')
assert valid.json() == {'redirect_url': reverse('payments:receipt_detail', args=[receipt.public_id])}
receipt.refresh_from_db()
assert receipt.current_version == 2 and receipt.revisions.count() == 2
assert 'نسخه اصلاحی ثبت شد' in client.get(valid.json()['redirect_url']).content.decode()
def grant(user, code):
user.user_permissions.add(Permission.objects.get(content_type__app_label='payments',codename=code))
for attr in ['_perm_cache','_user_perm_cache','_group_perm_cache']:
@@ -234,7 +279,7 @@ def test_independent_receipt_and_server_date(case,client):
assert receipt.notice is None
assert receipt.revisions.get().paid_date == timezone.localdate()
client.force_login(case['outsider'])
response = client.get(reverse('staff_payments:desk'),{'kind':'independent'})
response = client.get(reverse('staff_payments:desk'),{'tab':'receipts','kind':'independent'})
assert receipt.number in response.content.decode()
assert client.get(reverse('staff_payments:count')).json()['pending_receipts'] == 1
@@ -414,7 +459,7 @@ def test_revision_retains_notice_snapshot_and_identifier(case):
services.revise_receipt(case['customer'], receipt.public_id, 1, form.cleaned_data)
revision = receipt.revisions.get(version=2)
assert revision.account_snapshot['account_number'] == '000123456'
assert revision.deposit_id == '000123'
assert revision.deposit_id == '123'
def test_financial_unit_sms_template_accepts_financial_tags(case):
@@ -723,7 +768,7 @@ def test_linked_receipt_rejection_history_and_staff_identity(case, client):
staff = client.get(reverse('staff_payments:receipt_detail', args=[receipt.public_id])).content.decode()
assert all(value in staff for value in ['مریم', 'امینی', 'اصفهان', 'گلپایگان', case['customer'].local_mobile])
assert 'افراد تعیین‌شده' not in staff
listing = client.get(reverse('staff_payments:desk'), {'q': 'گلپایگان'}).content.decode()
listing = client.get(reverse('staff_payments:desk'), {'tab': 'receipts', 'q': 'گلپایگان'}).content.decode()
assert 'مریم' in listing and 'ایجادکننده اعلامیه: creator' in listing
@@ -787,7 +832,7 @@ def test_customer_notice_has_independent_owned_detail_url(case, client):
assert staff.context['notice_data'][0]['url'] == reverse('staff_payments:notice_detail', args=[case['notice'].public_id])
@pytest.mark.parametrize('mobile,expected', [('09120009999','0912000999938'), ('09120009021','0912000902169'), ('09000000000','0900000000090')])
@pytest.mark.parametrize('mobile,expected', [('09120009999','912000999938'), ('09120009021','912000902169'), ('09000000000','900000000090')])
def test_deposit_identifier_reference_vectors(mobile, expected):
from apps.payments.deposit_identifier import generate_id_algorithm
assert generate_id_algorithm(mobile) == expected
@@ -800,7 +845,7 @@ def test_deposit_identifier_endpoint_uses_stored_mobile_and_permissions(case, cl
before = case['customer'].payment_notices.count()
response = client.post(endpoint, {'customer': case['customer'].pk, 'mobile': '09000000000'})
assert response.status_code == 200
assert response.json()['identifier'] == '0912000999938'
assert response.json()['identifier'] == '912000999938'
assert response['Cache-Control'] == 'no-store'
assert case['customer'].payment_notices.count() == before
assert client.get(endpoint).status_code == 405
@@ -813,3 +858,47 @@ def test_deposit_identifier_endpoint_uses_stored_mobile_and_permissions(case, cl
client.force_login(case['creator'])
PaymentAccessConfiguration.objects.update_or_create(singleton=1, defaults={'open_create':False})
assert client.post(endpoint, {'customer': case['customer'].pk}).status_code == 403
@pytest.mark.parametrize('value,expected', [('', ''), ('000', '0'), ('۰۰۰۱۲۳۰۴', '12304'),
('٠٠٩١٢٣٠٦', '912306'), (' 00123 ', '123'), ('manual-123', 'manual-123')])
def test_deposit_identifier_normalization(value, expected):
from apps.payments.deposit_identifier import normalize_deposit_identifier
assert normalize_deposit_identifier(value) == expected
def test_generator_strips_zeroes_after_calculating_check_digits():
from apps.payments.deposit_identifier import generate_id_algorithm
assert generate_id_algorithm('00009120009999') == '912000999938'
assert generate_id_algorithm('000') == '0'
assert generate_id_algorithm('invalid').startswith('Error:')
def test_notice_and_receipt_store_normalized_identifiers(case):
notice = case['notice']
notice.refresh_from_db()
assert notice.deposit_id == '123'
assert notice.account_snapshot['account_number'] == '000123456'
receipt = submit(case)
assert receipt.revisions.get(version=1).deposit_id == '123'
notice.deposit_id = '٠٠١٢٣٠٤'
notice.save(update_fields=['deposit_id'])
notice.refresh_from_db()
assert notice.deposit_id == '12304'
def test_existing_identifier_migration_preserves_bank_snapshot(case):
from importlib import import_module
from django.apps import apps
from django.db import connection
from apps.payments.models import PaymentNotice, PaymentReceiptRevision
receipt = submit(case)
PaymentNotice.objects.filter(pk=case['notice'].pk).update(deposit_id='۰۰۰۱۲۳۰۴')
PaymentReceiptRevision.objects.filter(receipt=receipt).update(deposit_id='00012304')
migration = import_module('apps.payments.migrations.0006_normalize_deposit_identifiers')
from types import SimpleNamespace
migration.normalize_existing_identifiers(apps, SimpleNamespace(connection=connection))
case['notice'].refresh_from_db()
assert case['notice'].deposit_id == '12304'
assert receipt.revisions.get(version=1).deposit_id == '12304'
assert case['notice'].account_snapshot['account_number'] == '000123456'