estelam ticket, varizha , others

This commit is contained in:
javad committed 2026-10-13 15:48:24 +03:30
1 parent 35a1ec1794
commit 6b546aad76
71 files changed
+2865 -191

No files matched your search

+3 -1
View File
@@ -28,7 +28,9 @@ def receipt_alert_context(revision):
def queue_receipt_alerts(revision, actor):
if actor.account_type != 'CUSTOMER' or actor.pk != revision.receipt.customer_id:
# Submission/revision services authorize staff before reaching this queue.
# Keep customer submissions restricted to their own receipt.
if actor.account_type != 'STAFF' and (actor.account_type != 'CUSTOMER' or actor.pk != revision.receipt.customer_id):
return
configuration = PaymentReceiptAlertConfiguration.objects.filter(pk=1).first()
if not configuration or not (configuration.bale_enabled or configuration.sms_enabled) or (revision.version > 1 and not configuration.notify_revisions):
+40 -2
View File
@@ -1,8 +1,46 @@
"""Bounded-query projections use only the current evidence revision for financial totals."""
from datetime import datetime, time, timedelta
from django.urls import reverse
from django.db.models import BigIntegerField, F, OuterRef, Subquery, Sum, Value
from django.db.models import BigIntegerField, Count, F, OuterRef, Q, Subquery, Sum, Value
from django.db.models.functions import Coalesce
from .models import PaymentReceiptRevision
from django.utils import timezone
from .models import PaymentReceipt, PaymentReceiptRevision
def daily_payment_summary(receipts, notices):
"""Summarize permission-scoped, unfiltered querysets in two aggregate queries.
Submission means initial receipt creation. Final outcomes use the current
revision's finalization time, including receipts submitted on earlier days.
Superseded revisions and partial votes never count as final outcomes.
"""
local_timezone = timezone.get_default_timezone()
today = timezone.localdate(timezone=local_timezone)
start = timezone.make_aware(datetime.combine(today, time.min), local_timezone)
end = timezone.make_aware(datetime.combine(today + timedelta(days=1), time.min), local_timezone)
current = PaymentReceiptRevision.objects.filter(
receipt_id=OuterRef('pk'), version=OuterRef('current_version'))
receipts = receipts.annotate(
summary_amount=Subquery(current.values('amount')[:1]),
summary_finalized_at=Subquery(current.values('cycle__finalized_at')[:1]))
submitted = Q(created_at__gte=start, created_at__lt=end)
finalized = Q(summary_finalized_at__gte=start, summary_finalized_at__lt=end)
approved = finalized & Q(status=PaymentReceipt.Status.APPROVED)
rejected = finalized & Q(status=PaymentReceipt.Status.REJECTED)
pending = Q(status__in=[PaymentReceipt.Status.PENDING, PaymentReceipt.Status.PARTIAL])
summary = receipts.aggregate(
submitted_count=Count('pk', filter=submitted),
submitted_amount=Sum('summary_amount', filter=submitted, default=0),
approved_count=Count('pk', filter=approved),
approved_amount=Sum('summary_amount', filter=approved, default=0),
rejected_count=Count('pk', filter=rejected),
rejected_amount=Sum('summary_amount', filter=rejected, default=0),
pending_count=Count('pk', filter=pending),
pending_amount=Sum('summary_amount', filter=pending, default=0))
summary['notice_count'] = notices.filter(created_at__gte=start, created_at__lt=end).count()
summary['date'] = today
return summary
def notice_sms_history(notice):
+3 -1
View File
@@ -279,6 +279,7 @@ def desk(request):
mine = tab == 'receipts' and (request.GET.get('mine') == '1' or ('tab' not in request.GET and 'mine' not in request.GET))
receipts = selectors.receipts_with_current_values(policies.visible(PaymentReceipt.objects.select_related('customer__customer_profile', 'notice__created_by__staff_profile'), request.user))
notice_items = selectors.notices_with_totals(policies.visible(PaymentNotice.objects.select_related('customer__customer_profile', 'created_by__staff_profile', 'account'), request.user))
daily_summary = selectors.daily_payment_summary(receipts, notice_items)
if tab == 'notices':
items = filtered(notice_items, request)
state = request.GET.get('notice_state', '')
@@ -318,7 +319,8 @@ def desk(request):
else:
query.pop('mine', None)
return render(request, 'payments/desk.html', staff_context(page_obj=page, tab=tab, mine=mine, statuses=PaymentReceipt.Status.choices,
can_create=policies.can_create(request.user), banks=CompanyBankAccount.objects.all(), query_string=query.urlencode()))
can_create=policies.can_create(request.user), banks=CompanyBankAccount.objects.all(), query_string=query.urlencode(),
daily_summary=daily_summary))
@financial_required(staff=True)