add payment_link and banks
This commit is contained in:
1 parent
2ae79b1ca4
commit
de3135b588
100 files changed
+6167
-47
No files matched your search
@@ -0,0 +1,127 @@
|
||||
import uuid
|
||||
import jdatetime
|
||||
from django import forms
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from apps.accounts.models import User
|
||||
from . import validators
|
||||
from .models import BankInstitution, CompanyBankAccount, PaymentNotice
|
||||
|
||||
|
||||
class BankAccountForm(forms.ModelForm):
|
||||
revision_token = forms.CharField(required=False, widget=forms.HiddenInput)
|
||||
|
||||
class Meta:
|
||||
model = CompanyBankAccount
|
||||
fields = ['revision_token', 'name', 'bank', 'holder', 'account_number', 'iban', 'card_number', 'requires_deposit_id', 'is_active', 'available_to_staff', 'available_to_customers', 'sort_order']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.instance.pk:
|
||||
self.initial['revision_token'] = self.instance.updated_at.isoformat()
|
||||
|
||||
def clean_account_number(self):
|
||||
return validators.bank_number(self.cleaned_data['account_number'])
|
||||
|
||||
def clean_card_number(self):
|
||||
value = validators.bank_number(self.cleaned_data['card_number'])
|
||||
if value and (len(value) != 16 or sum((int(n) * (2 if i % 2 == 0 else 1)) // 10 + (int(n) * (2 if i % 2 == 0 else 1)) % 10 for i, n in enumerate(value)) % 10):
|
||||
raise forms.ValidationError('شماره کارت ۱۶ رقمی معتبر وارد کنید.')
|
||||
return value
|
||||
|
||||
def clean_iban(self):
|
||||
return validators.iban(self.cleaned_data['iban'])
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
if self.instance.pk and data.get('revision_token') != self.instance.updated_at.isoformat():
|
||||
raise forms.ValidationError('حساب از زمان باز کردن فرم تغییر کرده است؛ صفحه را تازه کنید و تغییرات را دوباره بررسی کنید.')
|
||||
if not any(data.get(key) for key in ('account_number', 'iban', 'card_number')):
|
||||
raise forms.ValidationError('حداقل شماره حساب، شبا یا کارت را وارد کنید.')
|
||||
return data
|
||||
|
||||
|
||||
class NoticeForm(forms.Form):
|
||||
submission_key = forms.UUIDField(widget=forms.HiddenInput)
|
||||
customer = forms.ModelChoiceField(label='مشتری', queryset=User.objects.none(), widget=forms.HiddenInput,
|
||||
error_messages={'required': 'مشتری را از نتایج جستوجو انتخاب کنید.',
|
||||
'invalid_choice': 'مشتری انتخابشده معتبر یا فعال نیست؛ دوباره جستوجو کنید.'})
|
||||
account = forms.ModelChoiceField(label='حساب مقصد', queryset=CompanyBankAccount.objects.none())
|
||||
subject = forms.CharField(label='موضوع', max_length=200)
|
||||
amount = forms.CharField(label='مبلغ (ریال)')
|
||||
deposit_id = forms.CharField(label='شناسه واریز', max_length=100, required=False)
|
||||
invoice_number = forms.CharField(label='شماره فاکتور', max_length=100, required=False)
|
||||
description = forms.CharField(label='توضیحات', required=False, widget=forms.Textarea)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.initial.setdefault('submission_key', uuid.uuid4())
|
||||
self.fields['customer'].queryset = User.objects.filter(account_type='CUSTOMER', is_active=True).select_related('customer_profile')
|
||||
self.fields['customer'].label_from_instance = lambda u: f'{getattr(u, "customer_profile", u)} — {u.local_mobile}'
|
||||
self.fields['account'].queryset = CompanyBankAccount.objects.filter(is_active=True, available_to_staff=True).select_related('bank')
|
||||
|
||||
def clean_amount(self):
|
||||
return validators.amount(self.cleaned_data['amount'])
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
if data.get('account') and data['account'].requires_deposit_id and not data.get('deposit_id', '').strip():
|
||||
self.add_error('deposit_id', 'این حساب شناسهدار است؛ شناسه واریز مشتری را حتماً وارد کنید.')
|
||||
return data
|
||||
|
||||
|
||||
class ReceiptForm(forms.Form):
|
||||
receipt_mode = forms.ChoiceField(label='نوع واریز', choices=[('linked', 'واریز مرتبط (پیشنهادی)'), ('independent', 'واریز مستقل')], widget=forms.RadioSelect, initial='linked')
|
||||
notice_id = forms.ModelChoiceField(label='اعلامیه واریز', queryset=PaymentNotice.objects.none(), required=False)
|
||||
paid_amount = forms.CharField(label='مبلغ پرداختشده (ریال)')
|
||||
destination_account = forms.ModelChoiceField(label='به کدام حساب ما واریز کردید؟', queryset=CompanyBankAccount.objects.none())
|
||||
deposit_id = forms.CharField(label='شناسه واریز که با آن پرداخت انجام دادهاید (اختیاری)', max_length=100, required=False)
|
||||
origin_bank = forms.ModelChoiceField(label='بانک مبدأ (اختیاری)', queryset=BankInstitution.objects.filter(is_active=True), required=False)
|
||||
origin_other = forms.CharField(label='نام بانک دیگر (اختیاری)', max_length=100, required=False)
|
||||
paid_day = forms.ChoiceField(label='روز', choices=[('', 'روز')] + [(str(i), str(i)) for i in range(1, 32)])
|
||||
paid_month = forms.ChoiceField(label='ماه', choices=[('', 'ماه')] + list(zip(map(str, range(1, 13)), ['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'])))
|
||||
paid_year = forms.ChoiceField(label='سال')
|
||||
receipt_image = forms.FileField(label='تصویر فیش')
|
||||
tracking_number = forms.CharField(label='شماره پیگیری (اختیاری)', max_length=100, required=False)
|
||||
description = forms.CharField(label='توضیحات (اختیاری)', required=False, widget=forms.Textarea)
|
||||
submission_key = forms.UUIDField(widget=forms.HiddenInput)
|
||||
|
||||
def __init__(self, *args, customer, notice_ids=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
notices = PaymentNotice.objects.filter(customer=customer, cancelled_at__isnull=True)
|
||||
if notice_ids is not None:
|
||||
notices = notices.filter(pk__in=notice_ids)
|
||||
self.fields['notice_id'].queryset = notices
|
||||
self.fields['notice_id'].label_from_instance = lambda n: f'{n.subject} — {n.amount:,} ریال — {n.invoice_number}'
|
||||
accounts = Q(is_active=True, available_to_customers=True) | Q(is_active=True, paymentnotice__in=notices)
|
||||
self.fields['destination_account'].queryset = CompanyBankAccount.objects.filter(accounts).distinct()
|
||||
current = jdatetime.date.fromgregorian(date=timezone.localdate())
|
||||
self.fields['paid_year'].choices = [('', 'سال')] + [(str(y), str(y)) for y in range(current.year, current.year - 11, -1)]
|
||||
self.initial.setdefault('submission_key', uuid.uuid4())
|
||||
self.initial.setdefault('paid_month', str(current.month))
|
||||
self.initial.setdefault('paid_year', str(current.year))
|
||||
|
||||
def clean_paid_amount(self):
|
||||
return validators.amount(self.cleaned_data['paid_amount'])
|
||||
|
||||
def clean_receipt_image(self):
|
||||
upload = self.cleaned_data['receipt_image']
|
||||
self.image_metadata = validators.image(upload)
|
||||
return upload
|
||||
|
||||
def clean(self):
|
||||
data = super().clean()
|
||||
notice = data.get('notice_id') if data.get('receipt_mode') == 'linked' else None
|
||||
data['notice_id'] = notice
|
||||
if data.get('receipt_mode') == 'linked' and not notice:
|
||||
self.add_error('notice_id', 'اعلامیه را انتخاب کنید یا واریز مستقل را بزنید.')
|
||||
try:
|
||||
data['paid_date'] = validators.paid_date(data.get('paid_day'), data.get('paid_month'), data.get('paid_year'))
|
||||
if self.data.get('paid_date') and self.data['paid_date'] != data['paid_date'].isoformat():
|
||||
raise forms.ValidationError('تاریخ ارسالی با تاریخ انتخابشده سازگار نیست؛ دوباره انتخاب کنید.')
|
||||
except forms.ValidationError as error:
|
||||
self.add_error('paid_day', error)
|
||||
account = data.get('destination_account')
|
||||
if account and not account.available_to_customers and (not notice or notice.account_id != account.pk):
|
||||
self.add_error('destination_account', 'این حساب فقط برای اعلامیه مربوط به آن قابل انتخاب است.')
|
||||
return data
|
||||
Reference in new issue
Block a user