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

+42 -3
View File
@@ -17,6 +17,36 @@ def actor_name(actor):
return getattr(profile, 'display_name', '') or actor.get_full_name() or actor.username
@transaction.atomic
def resend_notice_sms(actor, notice, request_key):
from uuid import UUID
from .notifications import context, notice_sms_pending
from .models import PaymentNotification
from apps.notifications.services import enqueue
if not policies.can_create(actor, notice.owning_unit) or not policies.notice_actions(PaymentNotice.objects.filter(pk=notice.pk), actor).exists():
raise PermissionDenied
try:
key = str(UUID(str(request_key)))
except (ValueError, TypeError, AttributeError):
raise ValidationError('درخواست ارسال معتبر نیست؛ صفحه را دوباره باز کنید.')
# Same customer -> notice lock order as issuance, receipt submission and deletion.
customer = User.objects.select_for_update().get(pk=notice.customer_id)
notice = PaymentNotice.objects.select_for_update().get(pk=notice.pk)
if notice.deleted_at or notice.cancelled_at or not customer.is_active or not customer.mobile:
raise ValidationError('این اعلامیه یا مشتری امکان ارسال پیامک ندارد.')
dedupe_key = f'payment-notice:{notice.public_id}:resend:{key}'
previous = PaymentNotification.objects.filter(notice=notice, job__dedupe_key=dedupe_key).select_related('job').first()
if previous:
return previous.job
if notice_sms_pending(notice):
raise ValidationError('پیامک این اعلامیه در صف یا در حال ارسال است؛ تا پایان تلاش جاری منتظر بمانید.')
job = enqueue('SMS', 'PAYMENT_NOTICE_CREATED', None, dedupe_key, customer=customer, staff_user=actor)
PaymentNotification.objects.create(job=job, notice=notice, unit=notice.owning_unit,
context=context(customer, notice=notice, amount=notice.amount))
audit(actor, 'NOTICE_SMS_RESEND_REQUESTED', notice, {'job_id': job.pk})
return job
def audit(actor, action, obj, details=None):
return PaymentAuditEvent.objects.create(actor=actor, actor_name=actor_name(actor) if actor else 'SYSTEM',
action=action, object_type=obj._meta.label_lower, object_id=str(getattr(obj, 'public_id', obj.pk)), details=details or {})
@@ -24,7 +54,10 @@ def audit(actor, action, obj, details=None):
def configuration_snapshot(obj):
"""Serialize only the financial configuration passed here, including flags and M2M IDs."""
return json.loads(serializers.serialize('json', [obj]))[0]['fields']
snapshot = json.loads(serializers.serialize('json', [obj]))[0]['fields']
if 'bale_token' in snapshot:
snapshot['bale_token'] = '[configured]' if snapshot['bale_token'] else ''
return snapshot
@transaction.atomic
@@ -60,7 +93,8 @@ def issue_notice(actor, data):
account = CompanyBankAccount.objects.select_for_update(of=('self',)).select_related('bank').get(pk=data['account'].pk)
if not account.is_active or not account.available_to_staff:
raise ValidationError('این حساب دیگر برای صدور اعلامیه فعال نیست.')
deposit_id = validators.digits(data.get('deposit_id', ''))
from .deposit_identifier import normalize_deposit_identifier
deposit_id = normalize_deposit_identifier(data.get('deposit_id', ''))
if account.requires_deposit_id and not deposit_id:
raise ValidationError('برای این حساب شناسه واریز مشتری الزامی است.')
key = data.get('submission_key')
@@ -108,9 +142,10 @@ def assign_cycle(revision, actor):
def receipt_metadata(data):
from .deposit_identifier import normalize_deposit_identifier
return {'amount': data['paid_amount'], 'paid_date': data['paid_date'], 'destination': data['destination_account'],
'origin_bank': data.get('origin_bank'), 'origin_other': data.get('origin_other', ''),
'deposit_id': validators.digits(data.get('deposit_id', '')), 'tracking_number': data.get('tracking_number', ''),
'deposit_id': normalize_deposit_identifier(data.get('deposit_id', '')), 'tracking_number': data.get('tracking_number', ''),
'description': data.get('description', '')}
@@ -156,6 +191,8 @@ def _submit_receipt(actor, customer, data, file_info, created_files):
created_files.append((revision.image.storage, revision.image.name))
assign_cycle(revision, actor)
audit(actor, 'RECEIPT_SUBMITTED', receipt, {'version': 1, 'amount': str(revision.amount), 'sha256': revision.sha256})
from .receipt_alerts import safe_queue_receipt_alerts
safe_queue_receipt_alerts(revision, actor)
return receipt
@@ -302,6 +339,8 @@ def revise_receipt(actor, receipt_id, version, data):
receipt.status='PENDING'
receipt.save(update_fields=['current_version','status','updated_at'])
audit(actor,'RECEIPT_REVISED',receipt,{'version':new_version,'previous_version':version,'sha256':revision.sha256})
from .receipt_alerts import safe_queue_receipt_alerts
safe_queue_receipt_alerts(revision, actor)
return receipt
except Exception:
for storage,name in created_files: