Files
customerTicket/tests/e2e/test_payments_e2e.py
T
2026-10-06 15:06:35 +03:30

376 lines
27 KiB
Python

import base64
import pytest
from django.contrib.auth.models import Permission
from django.urls import reverse
from playwright.sync_api import expect
from apps.accounts.models import User
from apps.staff.models import StaffProfile
from apps.attachments.models import AttachmentPolicy
from apps.payments.models import BankInstitution, CompanyBankAccount, PaymentApprovalPolicy
from apps.payments import services
from tests.e2e.pages.auth import AuthenticationPage
from tests.e2e.pages.payments import PaymentsPage
pytestmark=[pytest.mark.e2e,pytest.mark.django_db(transaction=True)]
PASSWORD='PaymentE2e-safe-2026'
PNG=base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=')
@pytest.fixture
def payment_case(settings,tmp_path):
settings.MEDIA_ROOT=tmp_path
bank,_=BankInstitution.objects.get_or_create(code='melli',defaults={'name':'ملی'})
account=CompanyBankAccount.objects.create(name='حساب فروش شرکت',holder='شرکت',bank=bank,account_number='000123')
customer=User.objects.create_user(username='payment-e2e-customer',mobile='09120009021',password=PASSWORD,account_type='CUSTOMER')
reviewers=[]
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}')
reviewers.append(user)
policy=PaymentApprovalPolicy.objects.create(name='تأیید هر دو نفر')
policy.reviewers.add(*reviewers)
AttachmentPolicy.objects.update_or_create(attachment_type='IMAGE',defaults={'max_file_size':10*1024*1024,'allowed_extensions':['.png'],'allowed_mime_types':['image/png']})
return customer,account,reviewers
def test_customer_hub_no_history_and_small_mobile_services(live_server,browser_page,payment_case):
customer,account,reviewers=payment_case
with browser_page() as page:
page.set_viewport_size({'width':320,'height':568})
AuthenticationPage(page,live_server.url).login_customer(customer,PASSWORD)
PaymentsPage(page,live_server.url).open_hub()
expect(page.get_by_role('heading',name='درخواست‌های اخیر شما')).to_have_count(0)
for name in ['ارتباط با کارشناسان','ارسال فیش واریزی','شماره حساب‌ها']:
expect(page.get_by_role('heading',name=name,exact=True)).to_be_in_viewport()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
page.get_by_role('link',name='ثبت درخواست',exact=True).click()
expect(page).to_have_url(live_server.url+reverse('tickets:new'))
def test_independent_receipt_and_two_person_approval(live_server,browser_page,payment_case):
customer,account,reviewers=payment_case
with browser_page() as page:
AuthenticationPage(page,live_server.url).login_customer(customer,PASSWORD)
PaymentsPage(page,live_server.url).send_receipt(account.pk,PNG)
expect(page.get_by_text('واریز مستقل',exact=True)).to_be_visible()
# Read the public identifier from real navigation; no ORM inside Playwright's loop.
receipt_id=page.url.rstrip('/').rsplit('/',1)[-1]
page.goto(live_server.url+reverse('accounts:staff_login'))
# Explicit logout using the real page control preserves session/CSRF behavior.
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)
expect(page.get_by_text('تأیید ناقص',exact=True)).to_be_visible()
page.get_by_role('button',name='خروج',exact=True).first.click()
AuthenticationPage(page,live_server.url).login_staff(reviewers[1],PASSWORD)
PaymentsPage(page,live_server.url).approve(receipt_id)
expect(page.get_by_text('تأیید شده',exact=True)).to_be_visible()
expect(page.get_by_role('button',name='ثبت تأیید من')).to_have_count(0)
def test_form_errors_focus_and_full_copy(live_server,browser_page,payment_case):
customer,account,reviewers=payment_case
notice=services.issue_notice(reviewers[0],{'customer':customer,'account':account,'amount':12345,'subject':'فاکتور نمونه','description':'توضیح ثابت و کامل','deposit_id':'00099'})
with browser_page() as page:
AuthenticationPage(page,live_server.url).login_customer(customer,PASSWORD)
page.goto(live_server.url+reverse('payments:receipt_new'))
page.get_by_role('button',name='ثبت و ارسال فیش').click()
expect(page.locator('#receipt-errors')).to_be_visible()
expect(page.locator('#id_paid_amount')).to_be_focused()
page.goto(live_server.url+reverse('payments:notices')+'?notice='+str(notice.public_id))
expect(page.get_by_text('توضیح ثابت و کامل',exact=True)).to_be_visible()
page.get_by_role('button',name='کپی کامل اطلاعات').click()
# Browser may deny Clipboard on LAN HTTP; accessible manual fallback is valid.
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:
assets=[]
page.on('request',lambda r:assets.append(r.url) if r.resource_type in {'script','stylesheet','font','image'} else None)
AuthenticationPage(page,live_server.url).login_customer(customer,PASSWORD)
page.goto(live_server.url+reverse('payments:receipt_new'))
amount=page.locator('#id_paid_amount')
amount.fill('12345')
expect(amount).to_have_value('۱۲٬۳۴۵')
expect(page.locator('#amount-words')).to_contain_text('دهم تومان')
amount.fill('12.5')
expect(amount).to_have_value('12.5')
page.get_by_role('button',name='ثبت و ارسال فیش').click()
expect(amount).to_be_focused()
expect(page.locator('#error-paid_amount')).to_contain_text('عدد صحیح')
page.locator('#id_paid_year').select_option('1403')
page.locator('#id_paid_month').select_option('12')
page.locator('#id_paid_day').select_option('30')
expect(page.locator('#paid-date-iso')).to_have_value('2025-03-20')
page.locator('#id_paid_year').select_option('1402')
expect(page.locator('#id_paid_day')).to_have_value('')
expect(page.locator('#paid-date-iso')).to_have_value('')
assert assets and all(url.startswith(live_server.url+'/') or url.startswith('data:') for url in assets)
def test_staff_issues_identifier_notice_and_customer_sends_linked_receipt(live_server,browser_page,payment_case):
customer,account,reviewers=payment_case
account.requires_deposit_id=True;account.save()
with browser_page() as page:
AuthenticationPage(page,live_server.url).login_staff(reviewers[0],PASSWORD)
page.goto(live_server.url+reverse('staff_payments:desk'))
page.get_by_role('link',name='ایجاد اعلامیه واریز',exact=True).click()
PaymentsPage(page,live_server.url).select_customer(customer.local_mobile)
page.locator('#id_account').select_option(str(account.pk))
page.locator('#id_subject').fill('پرداخت فاکتور اختصاصی')
page.locator('#id_amount').fill('100000')
expect(page.locator('#id_amount')).to_have_value('۱۰۰٬۰۰۰')
expect(page.locator('#id_deposit_id')).to_have_attribute('required','')
page.locator('#id_deposit_id').fill('۰۰۱۲۳')
page.locator('#id_description').fill('شناسه فقط برای همین واریز')
page.get_by_role('button',name='صدور و اطلاع‌رسانی').click()
expect(page.locator('.flash')).to_contain_text('اعلامیه صادر شد')
notice_id=page.url.rstrip('/').rsplit('/',1)[-1]
page.get_by_role('button',name='خروج',exact=True).first.click()
AuthenticationPage(page,live_server.url).login_customer(customer,PASSWORD)
page.goto(live_server.url+reverse('payments:notices')+'?notice='+notice_id)
expect(page.get_by_text('شناسه فقط برای همین واریز',exact=True)).to_be_visible()
page.get_by_role('link',name='ارسال فیش این واریز',exact=True).click()
expect(page.get_by_label('واریز مرتبط (پیشنهادی)',exact=True)).to_be_checked()
expect(page.locator('#id_destination_account')).to_have_value(str(account.pk))
expect(page.locator('#id_deposit_id')).to_have_value('00123')
page.locator('#id_paid_amount').fill('100000')
page.get_by_role('button',name='امروز',exact=True).click()
page.locator('#id_receipt_image').set_input_files({'name':'receipt.png','mimeType':'image/png','buffer':PNG})
page.get_by_role('button',name='ثبت و ارسال فیش').click()
expect(page.locator('.flash')).to_contain_text('فیش ثبت شد')
expect(page.get_by_text('واریز مستقل',exact=True)).to_have_count(0)
page.goto(live_server.url+reverse('payments:receipt_list'))
expect(page.locator('article.pay-card').filter(has_text='پرداخت فاکتور اختصاصی')).to_contain_text('در انتظار بررسی')
def test_staff_payment_filters_and_bank_selection(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
reviewers[0].user_permissions.add(Permission.objects.get(
content_type__app_label='payments', codename='manage_company_bankaccounts'))
CompanyBankAccount.objects.create(name='حساب دوم شرکت', holder='شرکت', bank=account.bank,
account_number='000456', is_active=False)
services.issue_notice(reviewers[0], {'customer': customer, 'account': account,
'amount': 100000, 'subject': 'پرداخت نمونه برای بررسی میز مالی', 'description': '', 'deposit_id': ''})
with browser_page() as page:
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
page.goto(live_server.url + reverse('staff_payments:desk'))
page.get_by_role('link', name='اعلامیه‌های واریز', exact=True).click()
expect(page.get_by_role('link', name='پرداخت نمونه برای بررسی میز مالی')).to_be_visible()
page.get_by_role('link', name='نیازمند اقدام من', exact=True).click()
page.get_by_role('button', name='جست‌وجو', exact=True).click()
expect(page.get_by_role('link', name='نیازمند اقدام من', exact=True)).to_have_attribute('aria-current', 'page')
expect(page.get_by_text('در حال حاضر فیشی برای اقدام شما وجود ندارد.', exact=True)).to_be_visible()
page.goto(live_server.url + reverse('staff_payments:banks'))
page.set_viewport_size({'width': 375, 'height': 812})
submit = page.get_by_role('button', name='اعمال بر انتخاب‌شده‌ها', exact=True)
expect(submit).to_be_disabled()
page.get_by_role('checkbox', name='انتخاب همه حساب‌های این صفحه', exact=True).check()
expect(submit).to_be_enabled()
expect(page.get_by_text('۲ حساب انتخاب شده', exact=True)).to_be_visible()
page.get_by_role('checkbox', name='انتخاب حساب دوم شرکت', exact=True).uncheck()
expect(page.get_by_text('۱ حساب انتخاب شده', exact=True)).to_be_visible()
expect(page.get_by_role('link', name='ویرایش', exact=True)).to_have_count(2)
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
def test_staff_bank_forms_and_receipt_customer_steps(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
reviewers[0].user_permissions.add(Permission.objects.get(
content_type__app_label='payments', codename='manage_company_bankaccounts'))
with browser_page() as page:
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
page.set_viewport_size({'width': 375, 'height': 812})
page.goto(live_server.url + reverse('staff_payments:bank_new'))
page.get_by_label('نام نمایشی حساب', exact=False).fill('حساب طراحی فرم')
page.locator('#id_bank').select_option(str(account.bank_id))
page.locator('#id_holder').fill('شرکت نمونه')
page.locator('#id_account_number').fill('123456789')
page.get_by_role('checkbox', name='شناسه واریز الزامی است', exact=False).check()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
page.get_by_role('button', name='ذخیره حساب', exact=True).click()
page.get_by_role('link', name='حساب طراحی فرم', exact=True).click()
expect(page.get_by_role('checkbox', name='شناسه واریز الزامی است', exact=False)).to_be_checked()
page.get_by_role('checkbox', name='قابل انتخاب کارشناسان', exact=False).uncheck()
page.get_by_role('button', name='ذخیره حساب', exact=True).click()
expect(page.locator('.pay-bank-row').filter(has_text='حساب طراحی فرم').get_by_text('غیرفعال', exact=True)).to_be_visible()
page.goto(live_server.url + reverse('staff_payments:receipt_customer'))
PaymentsPage(page,live_server.url).select_customer(customer.local_mobile)
page.get_by_role('button', name='ادامه', exact=True).click()
expect(page.get_by_role('heading', name='ثبت فیش برای مشتری', exact=True)).to_be_visible()
expect(page.locator('#id_paid_amount')).to_be_visible()
page.get_by_role('button', name='ثبت و ارسال فیش', exact=True).click()
expect(page.locator('#receipt-errors')).to_be_visible()
expect(page.locator('#id_paid_amount')).to_be_focused()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
def test_customer_search_disambiguation_and_context_shortcuts(live_server, browser_page, payment_case):
from tests.e2e.pages.ticket_notices import TicketNoticesPage
from apps.customers.models import CustomerProfile
from apps.tickets.models import Ticket, TicketCategory
from django.utils import timezone
customer, account, reviewers = payment_case
CustomerProfile.objects.create(user=customer, first_name='محمد', last_name='رضایی', organization_name='شرکت اول')
other = User.objects.create_user(username='other-payment-customer', mobile='09120009022', account_type='CUSTOMER')
CustomerProfile.objects.create(user=other, first_name='محمد', last_name='رضایی', organization_name='شرکت دوم')
ticket = Ticket.objects.create(customer=customer,
category=TicketCategory.objects.create(title='پرونده مالی', slug='finance-picker-e2e'),
subject='سابقه خرید برای انتخاب دقیق', owner=reviewers[0], selected_expert=reviewers[0],
origin_visibility='SELECTED', last_activity_at=timezone.now())
with browser_page() as page:
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
page.goto(live_server.url + reverse('staff_payments:notice_new'))
page.get_by_label('جست‌وجو و انتخاب مشتری', exact=False).fill('محمد رضایی')
expect(page.locator('.pay-customer-result')).to_have_count(2)
result = page.locator('.pay-customer-result').filter(has_text=customer.local_mobile)
result.locator('summary').click()
expect(result.get_by_role('link', name=ticket.ticket_number + ' · ' + ticket.subject)).to_be_visible()
result.get_by_role('button', name='انتخاب این مشتری', exact=True).click()
expect(page.locator('[data-selected-customer]')).to_contain_text('شرکت اول')
expect(page.locator('[data-selected-customer]')).to_contain_text(customer.local_mobile)
page.locator('#id_account').select_option(str(account.pk))
page.locator('#id_subject').fill('انتخاب مشتری باید دوباره انجام شود')
page.locator('#id_amount').fill('100000')
page.get_by_label('جست‌وجو و انتخاب مشتری', exact=False).fill('0912')
page.get_by_role('button', name='صدور و اطلاع‌رسانی', exact=True).click()
expect(page.get_by_label('جست‌وجو و انتخاب مشتری', exact=False)).to_be_focused()
page.goto(live_server.url + reverse('staff_tickets:detail', args=[ticket.public_id]))
TicketNoticesPage(page, live_server.url).toggle_notices()
page.locator('#customer-info').get_by_role('link', name='ایجاد اعلامیه واریز', exact=True).click()
expect(page).to_have_url(live_server.url + reverse('staff_payments:notice_new') + '?customer=' + str(customer.public_id))
expect(page.locator('[data-selected-customer]')).to_contain_text(customer.local_mobile)
page.goto(live_server.url + reverse('staff_tickets:contacts'))
page.locator('.contact-card').filter(has_text=customer.local_mobile).get_by_role('link', name='ایجاد اعلامیه واریز', exact=True).click()
expect(page.locator('[data-selected-customer]')).to_contain_text(customer.local_mobile)
def test_customer_finance_preview_and_notice_context(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
notice = services.issue_notice(reviewers[0], {'customer': customer, 'account': account,
'amount': 120000, 'subject': 'واریز مرتبط نمونه', 'description': 'توضیحات همیشه نمایان',
'invoice_number': 'INV-120', 'deposit_id': '00055'})
with browser_page() as page:
page.set_viewport_size({'width': 320, 'height': 568})
AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
page.goto(live_server.url + reverse('payments:notices') + '?notice=' + str(notice.public_id))
expect(page.get_by_text('توضیحات همیشه نمایان', exact=True)).to_be_visible()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
page.get_by_role('link', name='ارسال فیش این واریز').click()
expect(page.locator('[data-selected-notice-title]')).to_have_text(notice.subject)
expect(page.locator('[data-selected-notice-summary]')).to_contain_text('INV-120')
expect(page.locator('[data-selected-notice-link]')).to_have_attribute('href', reverse('payments:notice_detail', args=[notice.public_id]))
page.locator('#id_receipt_image').set_input_files({'name': 'receipt.png', 'mimeType': 'image/png', 'buffer': PNG})
expect(page.get_by_alt_text('پیش‌نمایش تصویر فیش')).to_be_visible()
expect(page.locator('#receipt-file-status')).to_contain_text('receipt.png')
page.get_by_role('button', name='حذف انتخاب').click()
expect(page.get_by_alt_text('پیش‌نمایش تصویر فیش')).to_be_hidden()
page.locator('#id_paid_amount').fill('120000')
page.get_by_role('button', name='امروز', exact=True).click()
page.get_by_role('button', name='ثبت و ارسال فیش').click()
expect(page.locator('#error-receipt_image')).to_be_visible()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
def test_customer_linked_receipt_status_and_reason_without_access_roster(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
notice = services.issue_notice(reviewers[0], {'customer': customer, 'account': account,
'amount': 12345, 'subject': 'بررسی فیش مرتبط', 'description': 'جزئیات واریز'})
with browser_page() as page:
AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
page.goto(live_server.url + reverse('payments:receipt_new') + '?notice=' + str(notice.public_id))
page.locator('#id_paid_amount').fill('12345')
page.get_by_role('button', name='امروز', exact=True).click()
page.locator('#id_receipt_image').set_input_files({'name': 'receipt.png', 'mimeType': 'image/png', 'buffer': PNG})
page.get_by_role('button', name='ثبت و ارسال فیش').click()
expect(page.locator('.flash')).to_contain_text('فیش ثبت شد')
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[1], PASSWORD)
page.goto(live_server.url + reverse('staff_payments:receipt_detail', args=[receipt_id]))
expect(page.get_by_role('button', name='ثبت تأیید من', exact=True)).to_be_visible()
expect(page.get_by_role('heading', name='افراد تعیین‌شده', exact=True)).to_have_count(0)
page.locator('#decision-reason').fill('تصویر فیش خوانا نیست')
page.get_by_role('button', name='رد فیش', exact=True).click()
expect(page.get_by_text('تصویر فیش خوانا نیست', exact=True)).to_be_visible()
page.get_by_role('button', name='خروج', exact=True).first.click()
AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
page.goto(live_server.url + reverse('payments:notices') + '?notice=' + str(notice.public_id))
expect(page.get_by_text('تصویر فیش خوانا نیست', exact=True)).to_be_visible()
page.get_by_role('link', name='جزئیات فیش و سوابق بررسی', exact=True).click()
expect(page.get_by_text('تصویر فیش خوانا نیست', exact=True)).to_be_visible()
expect(page.get_by_role('heading', name='افراد تعیین‌شده', exact=True)).to_have_count(0)
expect(page.get_by_role('heading', name='سوابق ارسال و اصلاح', exact=True)).to_be_visible()
def test_notice_permalink_and_staff_receipt_preview(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
notice = services.issue_notice(reviewers[0], {'customer': customer, 'account': account,
'amount': 12000, 'subject': 'واریز با لینک مستقل', 'description': 'اطلاعات واریز'})
with browser_page() as page:
page.set_viewport_size({'width': 375, 'height': 812})
AuthenticationPage(page, live_server.url).login_customer(customer, PASSWORD)
page.goto(live_server.url + reverse('payments:notices'))
page.get_by_role('link', name='جزئیات واریز و فیش‌ها', exact=True).click()
expect(page).to_have_url(live_server.url + reverse('payments:notice_detail', args=[notice.public_id]))
expect(page.get_by_text('اطلاعات واریز', exact=True)).to_be_visible()
page.get_by_role('link', name='ارسال فیش این واریز', exact=True).click()
page.locator('[data-selected-notice-link]').click()
expect(page).to_have_url(live_server.url + reverse('payments:notice_detail', args=[notice.public_id]))
page.get_by_role('button', name='خروج', exact=True).first.click()
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
page.goto(live_server.url + reverse('staff_payments:receipt_new', args=[customer.public_id]) + '?notice=' + str(notice.public_id))
expect(page.get_by_role('heading', name='ثبت فیش برای مشتری', exact=True)).to_be_visible()
expect(page.locator('[data-selected-notice-link]')).to_have_attribute('href', reverse('staff_payments:notice_detail', args=[notice.public_id]))
page.locator('#id_paid_amount').fill('12000')
page.get_by_role('button', name='امروز', exact=True).click()
page.locator('#id_receipt_image').set_input_files({'name': 'receipt.png', 'mimeType': 'image/png', 'buffer': PNG})
expect(page.get_by_alt_text('پیش‌نمایش تصویر فیش')).to_be_visible()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
page.get_by_role('button', name='ثبت و ارسال فیش', exact=True).click()
expect(page.locator('.flash')).to_contain_text('فیش ثبت شد')
def test_notice_identifier_generation_preserves_manual_value_and_customer_context(live_server, browser_page, payment_case):
customer, account, reviewers = payment_case
account.requires_deposit_id = True
account.save()
with browser_page() as page:
page.set_viewport_size({'width': 375, 'height': 812})
AuthenticationPage(page, live_server.url).login_staff(reviewers[0], PASSWORD)
page.goto(live_server.url + reverse('staff_payments:notice_new'))
generate = page.get_by_role('button', name='تولید خودکار شناسه', exact=True)
expect(generate).to_be_disabled()
PaymentsPage(page, live_server.url).select_customer(customer.local_mobile)
page.locator('#id_account').select_option(str(account.pk))
expect(page.locator('#id_deposit_id')).to_have_attribute('required', '')
generate.click()
expect(page.locator('#id_deposit_id')).to_have_value('0912000902169')
page.locator('#id_deposit_id').fill('manual-123')
generate.click()
expect(page.locator('#identifier-candidate')).to_have_text('0912000902169')
expect(page.locator('#id_deposit_id')).to_have_value('manual-123')
page.get_by_role('button', name='جایگزینی شناسه', exact=True).click()
expect(page.locator('#id_deposit_id')).to_have_value('0912000902169')
page.get_by_role('button', name='تغییر مشتری', exact=True).click()
expect(page.locator('#id_deposit_id')).to_have_value('')
expect(generate).to_be_disabled()
assert page.evaluate('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')