before push
This commit is contained in:
commit
3a08268c12
@ -35,9 +35,9 @@ from pathlib import Path
|
||||
# }
|
||||
# )
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "car_inventory.settings")
|
||||
django.setup()
|
||||
# django.setup()
|
||||
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
# BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
app = get_asgi_application()
|
||||
|
||||
# app = WhiteNoise(app, root=str(BASE_DIR / 'staticfiles'))
|
||||
@ -50,7 +50,7 @@ application = ProtocolTypeRouter(
|
||||
path("sse/notifications/", NotificationSSEApp()),
|
||||
re_path(
|
||||
r"", app
|
||||
), # All other routes go to Django
|
||||
),
|
||||
]
|
||||
)
|
||||
),
|
||||
@ -58,5 +58,5 @@ application = ProtocolTypeRouter(
|
||||
)
|
||||
|
||||
|
||||
if django.conf.settings.DEBUG:
|
||||
application = ASGIStaticFilesHandler(app)
|
||||
# if django.conf.settings.DEBUG:
|
||||
# application = ASGIStaticFilesHandler(app)
|
||||
@ -5,7 +5,7 @@ from django.urls import path, include
|
||||
from schema_graph.views import Schema
|
||||
from django.conf.urls.static import static
|
||||
from django.conf.urls.i18n import i18n_patterns
|
||||
from inventory.notifications.sse import NotificationSSEApp
|
||||
# from inventory.notifications.sse import NotificationSSEApp
|
||||
|
||||
# import debug_toolbar
|
||||
# from two_factor.urls import urlpatterns as tf_urls
|
||||
|
||||
@ -1,82 +1,3 @@
|
||||
# import json
|
||||
# from django.contrib.auth.models import AnonymousUser
|
||||
# from django.contrib.auth import get_user_model
|
||||
# from django.db import close_old_connections
|
||||
# from urllib.parse import parse_qs
|
||||
# from channels.db import database_sync_to_async
|
||||
# from inventory.models import Notification
|
||||
# import asyncio
|
||||
|
||||
# @database_sync_to_async
|
||||
# def get_notifications(user, last_id):
|
||||
# return Notification.objects.filter(
|
||||
# user=user, id__gt=last_id, is_read=False
|
||||
# ).order_by("created")
|
||||
|
||||
# class NotificationSSEApp:
|
||||
# async def __call__(self, scope, receive, send):
|
||||
# if scope["type"] != "http":
|
||||
# return
|
||||
|
||||
# query_string = parse_qs(scope["query_string"].decode())
|
||||
# last_id = int(query_string.get("last_id", [0])[0])
|
||||
|
||||
# # Get user from scope if using AuthMiddlewareStack
|
||||
# user = scope.get("user", AnonymousUser())
|
||||
# if not user.is_authenticated:
|
||||
# await send({
|
||||
# "type": "http.response.start",
|
||||
# "status": 403,
|
||||
# "headers": [(b"content-type", b"text/plain")],
|
||||
# })
|
||||
# await send({
|
||||
# "type": "http.response.body",
|
||||
# "body": b"Unauthorized",
|
||||
# })
|
||||
# return
|
||||
|
||||
# await send({
|
||||
# "type": "http.response.start",
|
||||
# "status": 200,
|
||||
# "headers": [
|
||||
# (b"content-type", b"text/event-stream"),
|
||||
# (b"cache-control", b"no-cache"),
|
||||
# (b"x-accel-buffering", b"no"),
|
||||
# ]
|
||||
# })
|
||||
|
||||
# try:
|
||||
# while True:
|
||||
# close_old_connections()
|
||||
|
||||
# notifications = await get_notifications(user, last_id)
|
||||
# for notification in notifications:
|
||||
# data = {
|
||||
# "id": notification.id,
|
||||
# "message": notification.message,
|
||||
# "created": notification.created.isoformat(),
|
||||
# "is_read": notification.is_read,
|
||||
# }
|
||||
|
||||
# event_str = (
|
||||
# f"id: {notification.id}\n"
|
||||
# f"event: notification\n"
|
||||
# f"data: {json.dumps(data)}\n\n"
|
||||
# )
|
||||
|
||||
# await send({
|
||||
# "type": "http.response.body",
|
||||
# "body": event_str.encode("utf-8"),
|
||||
# "more_body": True
|
||||
# })
|
||||
|
||||
# last_id = notification.id
|
||||
|
||||
# await asyncio.sleep(2)
|
||||
|
||||
# except asyncio.CancelledError:
|
||||
# pass
|
||||
|
||||
import json
|
||||
import time
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
|
||||
@ -5126,11 +5126,11 @@ class EstimatePrintView(EstimateDetailView):
|
||||
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
|
||||
self.object = self.get_object()
|
||||
context = self.get_context_data(object=self.object)
|
||||
|
||||
|
||||
|
||||
|
||||
# lang = request.GET.get('lang', 'ar')
|
||||
|
||||
|
||||
@ -5148,7 +5148,7 @@ class EstimatePrintView(EstimateDetailView):
|
||||
|
||||
response = HttpResponse(pdf_file, content_type='application/pdf')
|
||||
response['Content-Disposition'] = f'attachment; filename="estimate_{self.object.estimate_number}.pdf"'
|
||||
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@ -10273,7 +10273,8 @@ def payment_callback(request, dealer_slug):
|
||||
# return render(request, "payment_failed.html", {"message": message})
|
||||
|
||||
@login_required
|
||||
async def sse_stream(request): # 👈 Mark as async!
|
||||
async def sse_stream(request):
|
||||
import asyncio
|
||||
def event_generator():
|
||||
last_id = int(request.GET.get("last_id", 0))
|
||||
|
||||
@ -11052,18 +11053,18 @@ class PurchaseOrderDetailView(LoginRequiredMixin, PermissionRequiredMixin, Detai
|
||||
"item_model", "bill_model"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
if self.object.po_status == 'fulfilled':
|
||||
context['po_items_list']=po_items_qs
|
||||
context['vendor']=po_items_qs.first().bill_model.vendor
|
||||
context['dealer']=request.dealer
|
||||
|
||||
|
||||
# Check if PDF format is requested
|
||||
if request.GET.get('format') == 'pdf':
|
||||
# Use a separate, print-friendly template for the PDF
|
||||
if request.GET.get('lang')=='en':
|
||||
html_string = render_to_string(
|
||||
"purchase_orders/po_detail_en_pdf.html",
|
||||
"purchase_orders/po_detail_en_pdf.html",
|
||||
context
|
||||
)
|
||||
else:
|
||||
|
||||
@ -87,9 +87,13 @@
|
||||
didOpen: (toast) => {
|
||||
toast.onmouseenter = Swal.stopTimer;
|
||||
toast.onmouseleave = Swal.resumeTimer;
|
||||
} });
|
||||
}
|
||||
});
|
||||
|
||||
{% with last_notif=notifications_|last %}
|
||||
let lastNotificationId = {{ last_notif.id|default:0 }};
|
||||
{% endwith %}
|
||||
|
||||
let lastNotificationId = {{ notifications_.last.id|default:0 }};
|
||||
let seenNotificationIds = new Set();
|
||||
let counter = document.getElementById('notification-counter');
|
||||
let notificationsContainer = document.getElementById('notifications-container');
|
||||
@ -100,7 +104,6 @@
|
||||
let initialUnreadCount = {{ notifications_.count|default:0 }};
|
||||
updateCounter(initialUnreadCount);
|
||||
|
||||
|
||||
fetchInitialNotifications();
|
||||
|
||||
function fetchInitialNotifications() {
|
||||
@ -108,29 +111,22 @@
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.notifications && data.notifications.length > 0) {
|
||||
|
||||
lastNotificationId = data.notifications[0].id;
|
||||
|
||||
seenNotificationIds = new Set();
|
||||
|
||||
let unreadCount = 0;
|
||||
|
||||
data.notifications.forEach(notification => {
|
||||
seenNotificationIds.add(notification.id);
|
||||
if (!notification.is_read) {
|
||||
unreadCount++;
|
||||
}
|
||||
if (!notification.is_read) unreadCount++;
|
||||
});
|
||||
|
||||
renderNotifications(data.notifications);
|
||||
|
||||
updateCounter(unreadCount);
|
||||
|
||||
|
||||
setTimeout(() => {
|
||||
connectSSE();
|
||||
}, 5000);
|
||||
}
|
||||
// Always connect SSE after initial load
|
||||
setTimeout(() => {
|
||||
connectSSE();
|
||||
}, 1000);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching initial notifications:', error);
|
||||
@ -143,12 +139,12 @@
|
||||
eventSource.close();
|
||||
}
|
||||
|
||||
// ✅ FIXED URL HERE
|
||||
eventSource = new EventSource("/sse/notifications/?last_id=" + lastNotificationId);
|
||||
|
||||
eventSource.addEventListener('notification', function(e) {
|
||||
try {
|
||||
const data = JSON.parse(e.data);
|
||||
|
||||
if (seenNotificationIds.has(data.id)) return;
|
||||
seenNotificationIds.add(data.id);
|
||||
|
||||
@ -158,6 +154,11 @@
|
||||
|
||||
updateCounter('increment');
|
||||
|
||||
if (!notificationsContainer) {
|
||||
console.warn("Notification container missing, can't render SSE event");
|
||||
return;
|
||||
}
|
||||
|
||||
const notificationElement = createNotificationElement(data);
|
||||
notificationsContainer.insertAdjacentHTML('afterbegin', notificationElement);
|
||||
|
||||
@ -168,7 +169,7 @@
|
||||
|
||||
Toast.fire({
|
||||
icon: 'info',
|
||||
html:`${data.message}`
|
||||
html: `${data.message}`
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
@ -220,7 +221,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
`;
|
||||
}
|
||||
|
||||
function updateCounter(action) {
|
||||
@ -231,12 +232,14 @@
|
||||
if (notificationCountDiv) {
|
||||
notificationCountDiv.innerHTML = `
|
||||
<span class="badge bg-danger rounded-pill" id="notification-counter" style="position: absolute; top: 8px; right: 3px; font-size: 0.50rem;">0</span>
|
||||
`;
|
||||
`;
|
||||
counter = document.getElementById('notification-counter');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!counter) return;
|
||||
|
||||
let currentCount = parseInt(counter.textContent) || 0;
|
||||
|
||||
if (action === 'increment') {
|
||||
@ -294,11 +297,11 @@
|
||||
notificationCard.closest('.notification-card').classList.add('fade-out');
|
||||
setTimeout(() => {
|
||||
notificationCard.closest('.notification-card').remove();
|
||||
}, 200);
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</script>
|
||||
Loading…
x
Reference in New Issue
Block a user