From 03f40cb8db2c6d2e107b9209a2ac3a5b39af41ad Mon Sep 17 00:00:00 2001 From: emile Date: Wed, 3 Jul 2024 11:11:55 +0300 Subject: [PATCH] new --- osinaweb/db.sqlite3 | Bin 1417216 -> 1417216 bytes .../__pycache__/consumers.cpython-310.pyc | Bin 4664 -> 4906 bytes .../__pycache__/models.cpython-310.pyc | Bin 6453 -> 7283 bytes .../support/__pycache__/urls.cpython-310.pyc | Bin 1426 -> 1448 bytes .../support/__pycache__/views.cpython-310.pyc | Bin 1840 -> 2666 bytes osinaweb/support/consumers.py | 15 +++- ...6_remove_ticketconnection_type_and_more.py | 22 +++++ .../0007_alter_ticketstaff_staff.py | 20 +++++ .../0008_alter_tickettask_ticket.py | 19 ++++ ...etconnection_type_and_more.cpython-310.pyc | Bin 0 -> 731 bytes ...07_alter_ticketstaff_staff.cpython-310.pyc | Bin 0 -> 845 bytes ...08_alter_tickettask_ticket.cpython-310.pyc | Bin 0 -> 754 bytes osinaweb/support/models.py | 84 ++++++++++++----- .../details_templates/ticket-room.html | 31 ++++--- .../details_templates/ticket-settings.html | 85 ++++++++++-------- osinaweb/support/urls.py | 2 +- osinaweb/support/views.py | 43 +++++++-- 17 files changed, 240 insertions(+), 81 deletions(-) create mode 100644 osinaweb/support/migrations/0006_remove_ticketconnection_type_and_more.py create mode 100644 osinaweb/support/migrations/0007_alter_ticketstaff_staff.py create mode 100644 osinaweb/support/migrations/0008_alter_tickettask_ticket.py create mode 100644 osinaweb/support/migrations/__pycache__/0006_remove_ticketconnection_type_and_more.cpython-310.pyc create mode 100644 osinaweb/support/migrations/__pycache__/0007_alter_ticketstaff_staff.cpython-310.pyc create mode 100644 osinaweb/support/migrations/__pycache__/0008_alter_tickettask_ticket.cpython-310.pyc diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index 2f06f225e9b779d0acc1774047baf2cf66f19591..4c7905b45a23e2577b3c9f574b8bed6f99b434e2 100644 GIT binary patch delta 5970 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 J1bqH{{%@Ot#-9KH diff --git a/osinaweb/support/__pycache__/consumers.cpython-310.pyc b/osinaweb/support/__pycache__/consumers.cpython-310.pyc index 03b3d2a0ea738190a22084b083adf4f3ccedee0b..33702a34a1a90ac9f17e413e574bbd101302aefc 100644 GIT binary patch delta 1798 zcmZ`(&2Jk;6yMohuh(m@?bvQylA=f?O|)$wp^z2KWS>AEF#$TEl z7m$o{XvLw(LNG@z&M}cVpb9BcFI?b{m;)D1ApQgjyf+)wsioSQ-@JYEzTcZUUOHON z_I%$n;J5M5gXWp}pRz|JYr$s%)_bt{@A5Ztb3aUutg&}sd__dE<+jp8qm_U~L}u(C z7@<3|h#|6Yl0t5n8j*1hq|Kqpsv@uXChCOV$Q;ic7(C{thnjn0C9SO#K(5#--6ya+ zu+H2!N!b`0985JxAAuCT%)`_}xLBqgeIbg+n zI|Noh^haQ-1Q+#YQ=fxa0mV>Oc_>z^hasq+l|PsZBqtx6Yqy$F8w@Kaq-`pwavF?+ zpmI@ML>;QEZtruI*+HwfSr5diN;D(Jg-Ta+c=|{=^oxiKF8?z>ShJMPX}ei1YF^ac zt2KJvE^UaY*Hyj_u-1=l9U3f<6>D(e6$mmzN+eG_GG{u(hQC9cC#8f^Jht9zXYKCJ=PoaYhlD2br!N&JXk_l1_1LbuvNWAyT>Uc8&VeFp@x+UKtlaN zHLk+T@XbpAahCSKw>W>_>j$TjD5NeA%b+z$ubT@@Ho!eF+U+M%a+WGO2|wMUv45jqcGa z@_YC1yiUyrO{n53Z1TI*^?f7`O{V?WcSWatNZ56haoM}D#Z9}0l#bE?3TF;d!g)}M zaM0=Vz|n1CTPUa9pjmbk;TFQPaj~nw>%ihAx$FH}`4C0c5w;O-10326U9pc4&=dPO z=3@I}KhL%PDu@haH$Aw9S+Um;&?el{XU&~VQ*3T3#MeRL>qm>3EV&bp1X?*M-djK` zw=v+N*Ma%77&7Aa>;eT0?RcW6z58(mPgPYu^yl8!7h>V5fjOk~R7}O{PM27ZgKo;I z{L4RIno8gb82UyoW{-1QkY^6f<^fb${*o{6LyUTsQD3Dej|LA?&%LaZ(Pr23&b>Scwij)AotMMIv4=NSC#Ym%{Orns_6lztOjqF81TtJ zupKyK6@)1dcYt>+WxoB%MLfmljom=NDPuSc44cWYAo>wusBy}QwukqHxd0faeluLd aCGI)ble;q&vMG;dw(}Fuv5s^L>;D5gd3PuP delta 1565 zcmZ`(&u<$=6yDiguh(m@W4m^nP#|eYfTd{?Bp@_E0hQ2FNFr!*=>coCJ5Ft!we@zk zQl&~pY7ycPfizbR$py(hQT0Io0l0EsF8l#pxFRBWZ#H5ZOIVt3#&6#5_su?h@ySAU z;JS{6KjuH^tj#>CK4evfe=S^Bam8QCU)biG!Z|D-X<_leWSXel(|T^NdY|EL;hMUy zGwq&sSUb|xUZ*|OZfc$_$NI&^)Y^{v-H3Z;YKd;}1s704*QqJ)4tZ*ZzTjR%zG}>} zn*7vQk>43D`KxiG%u+Mv{mxi}3-Y>|%s-Dt71m@m<}gb)naOl!G3#%qXfyL4+o&-4 zXQ?I4!nFLcQhN4nR2N#0^>ob9z-5Lk)DMiq!jUGg78Xaw7EGazXFv@%l@ruSP=T`~ zIERp0oo-)n$W>A+)E<{ z94^r1lEQgBrVg17qKF4#5&y?c1Pkk<3e987blBsn^(~uG>1E9;$6_#SV+Xs@9@OPe z#hYcy9hM0$$(Fs;TBReEhW@d~Z9fcoD7WpE(SMp=BQ<;RAW94Ufgi@Hv4_JsLw0#} zPF7vaqpY;FvZIE$J0!2FOE66)G}Nq5Gjw_eA+2S)?+f7vxA%D@aHhUIwjDMn?b2-H zWl}2eJ9q<^$ZA<$E-kRv<>#ey)2cyvmx{mx-o3+DGpbM*O*}od5|xYm#@QHc zplGava%|of`~5M4E2L(_TNHq%3YQ5~zC?8585Xxj$3mFw4`a_#LxXooPemfPaE;(2 zg43zN8z}4Gikot?{PWI-q~Z}=C%AzyHi1IH#{?7!KFOqWbXIZx*ZV7|lE_Xad5@}s ziv;8onS0vZ3D+`r6DcmC!RYaMx5`EtN61UoKX?t#sU0N9seKOUmIT>6w(*1l6*#w3 z(cP?rr@NXqpJvBr+z&)|5WxaPD0I3I3s_f!CZcD&nW({@Y`s!f!`hI)R~MTTg{`2Y z2XbcWNi}=Udd9)J{B3GBV>;QU<&y`7*~DHcf8i>%{CVfZhjq%39y8WIN9SDvHL8ge z=$-$7E2h`hU^;%B@Y8hc6y)97*RC?79B@3l(yd=vCw|;2CozY1EPRo~IZt2{?_i5y zBFGNP9?7rj{dZoV+m{GFARzJqaRg|_K>bi(9w3XSyeNP3a=CHVXxe3Yt+B(_`<*&x-zukH`Pyhe` diff --git a/osinaweb/support/__pycache__/models.cpython-310.pyc b/osinaweb/support/__pycache__/models.cpython-310.pyc index 0767b6366a63496c94cac406536ce962e50cd3e2..5f8acdc021caa867746aed61d22afff25e4fe7e8 100644 GIT binary patch delta 3548 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 delta 44 ycmZ3%J&Bt)pO=@50SIn}wWJ;1$lJ>-z+aM?oSj;tTbx=_l9`uYy!in03q}AQ#16Xv diff --git a/osinaweb/support/__pycache__/views.cpython-310.pyc b/osinaweb/support/__pycache__/views.cpython-310.pyc index 5ba7c531226beadfdabee6d138747667b762f3d3..0304ad4b7e9c8c7fd144eb1bf711c629be279e85 100644 GIT binary patch literal 2666 zcmZ`)OK)366uvX}>1UiYN?VYSRY<`ViCJ`os#4VQD1{(3>Bgd%8_y)U&V9Hu<0i4L zC8U;R#2@G)S>|uB>#BJO5NI>knMa ze>N=cz+W;T%wiq9 zWcJE%US<_DufV*@YGz(#^-Zg_a1NTR7S*2MDdR#f?sC=5w)?yXgXrG;ofGC9)3L3bzT5Y5o4Lp21Z+Je zV`qM^9~cS#^z@$f`106QC3DL)XTdQ&DW6*MbF*8?i`^0{AKS!wazj<;G}KP5v8U>N z_hjMJ0(}+G=jSxHb0_z5pH*MD<3KfXi`DYrnGMmXZ|H^IP^v89Vj!}eDCVQ3=|(pR zqjY^wCGn^gKZ7=$ed8RM+GeFQF%6(XcwibJWolTE2YHI%y2%hD7Q z7-gv(U1MB@Q7mV2WV_&A6IqrRe_D&$-wS1^lrUBZtV8W>8NYP37#|fj`$cU??Ll>-1>IVGNK0oZmL&kNvxbYBN(H=jHqyqLHcm_UCq-_?KI%vIa6#RE*R%<(qV}aGy zDrsNvCqpik2w*K1kzgdm5)kbbaS)eqXBl^Va9;64b!Lg{uzvYt`w>K0ws`{C!r1_O z%VJN3y(%lGgQsWgQ_Uu+D^hl?aDzMDIGu+4vO70JJ2PZG9IfCixir)$Hm7WPOJfei%|+q z>?Is=p;Mm;hfX|H9do%m2!+z~Mgse?y=`fe(pj0D+v^;6}?S zkZx(xSd3$k5}pEzOwq51DWKmBoM+J;U4JX!Nv>3s?#cr6DhB4n3TU1p(7l-|aRsfq zisT(+s1y(du(h+JJqZZFnF*j?!EC%~MuA?wcppU=c2f%NNg50cv(Drp>^JcZx{ zkEJd%-pfR&G9f$5=6Qf6U!U7unIvzb3!kn?K&c?s7xl6XkMzz?H_mpWv^zV;B$~Jw pd*-|_{+PB8Zh;lUnBPYHlvtGw>~#218@l~HdZkS0CHR-?phDti30Y2d6Vm!8U2i1ROAq7) zqP-!mAmvuxfakC{A#s2!FTjjRqaLuepT7C#XJ>YP@7}s@?l_hL-}kr6NujUYK3T4g z4sPm6Bh^BUC{&@1L{E*-sJNDxsTEok*OO*yhc;1|Lk(&!l@BCzfm^g$@fL8KIu-YT zyR=pDHuc^pe)|_*>#L>4SwAwHfX`E+yf}pkI$EQuq=pfh#JD962<`m<0QR$+hkMm5h_hPN^fxN2C zi6wv3hQybq*_VZ}Cnx&g)tYb>g4Zg4goy_TgDpG;R<<@h-_3&JpE^LjX4m-;%I%wn zVEXF$bs&$;J^97x_V^J<{0YLnda^VgHcwFu5RNgK9Lj-t+WmigZuZ+}+xQb;=YB_i zGEZ(wk6y&tG!Mo(X92E+Yv3+>8~N_#f+UY&n_Nd{d*fV)SyBY=M4E5|_2#x#HsK~H zVQ({a%5YN=XIG0EXO#QkVy4c#NfmhMeh&00O1@gmLXB4K9)B8mq9o?;M#*qdLi MSw!83W8rbhU!tzO+yDRo diff --git a/osinaweb/support/consumers.py b/osinaweb/support/consumers.py index 89135a40..7a987ab9 100644 --- a/osinaweb/support/consumers.py +++ b/osinaweb/support/consumers.py @@ -20,12 +20,20 @@ class TicketRoomConsumer(WebsocketConsumer): self.ticket = get_object_or_404(Ticket, id=self.ticket_id) self.ticket_number = self.ticket.ticket_number + existing_connection = TicketConnection.objects.filter(ticket=self.ticket, user=self.user, terminated=False).delete() TicketConnection.objects.create( ticket=self.ticket, user=self.user, - type='Online', date=datetime.now() ) + staff_profile = StaffProfile.objects.filter(user=self.user).first() + if staff_profile: + if not TicketStaff.objects.filter(staff=staff_profile, ticket=self.ticket).exists(): + TicketStaff.objects.create( + staff=staff_profile, + ticket=self.ticket, + date_added=datetime.now() + ) async_to_sync(self.channel_layer.group_add)( self.ticket_number, self.channel_name @@ -38,8 +46,7 @@ class TicketRoomConsumer(WebsocketConsumer): TicketConnection.objects.filter( ticket=self.ticket, user=self.user, - type='Online' - ).delete() + ).update(terminated=True) async_to_sync(self.channel_layer.group_discard)( self.ticket_number, self.channel_name ) @@ -164,7 +171,7 @@ class TicketRoomConsumer(WebsocketConsumer): })) def modify_online_user(self): - connections = TicketConnection.objects.filter(ticket=self.ticket, type='Online') + connections = TicketConnection.objects.filter(ticket=self.ticket, terminated=False) event = { 'type': 'user_connection_handler', 'user': self.user, diff --git a/osinaweb/support/migrations/0006_remove_ticketconnection_type_and_more.py b/osinaweb/support/migrations/0006_remove_ticketconnection_type_and_more.py new file mode 100644 index 00000000..8320f116 --- /dev/null +++ b/osinaweb/support/migrations/0006_remove_ticketconnection_type_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.5 on 2024-07-03 06:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('support', '0005_alter_ticketconnection_ticket'), + ] + + operations = [ + migrations.RemoveField( + model_name='ticketconnection', + name='type', + ), + migrations.AddField( + model_name='ticketconnection', + name='terminated', + field=models.BooleanField(default=False), + ), + ] diff --git a/osinaweb/support/migrations/0007_alter_ticketstaff_staff.py b/osinaweb/support/migrations/0007_alter_ticketstaff_staff.py new file mode 100644 index 00000000..692eb6fe --- /dev/null +++ b/osinaweb/support/migrations/0007_alter_ticketstaff_staff.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.5 on 2024-07-03 07:15 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('osinacore', '0085_rename_date_staffposition_start_date_and_more'), + ('support', '0006_remove_ticketconnection_type_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='ticketstaff', + name='staff', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.staffprofile'), + ), + ] diff --git a/osinaweb/support/migrations/0008_alter_tickettask_ticket.py b/osinaweb/support/migrations/0008_alter_tickettask_ticket.py new file mode 100644 index 00000000..7cb8b985 --- /dev/null +++ b/osinaweb/support/migrations/0008_alter_tickettask_ticket.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.5 on 2024-07-03 07:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('support', '0007_alter_ticketstaff_staff'), + ] + + operations = [ + migrations.AlterField( + model_name='tickettask', + name='ticket', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='support.ticket'), + ), + ] diff --git a/osinaweb/support/migrations/__pycache__/0006_remove_ticketconnection_type_and_more.cpython-310.pyc b/osinaweb/support/migrations/__pycache__/0006_remove_ticketconnection_type_and_more.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3aeb3eb417a1b343f1a2f9c6b2c48fa43d748b41 GIT binary patch literal 731 zcmZuvJ#Q2-5cSvH?QIe%RgkC<1=2OyG$0Cu5`;nnK_a5r#&T}vPJ8jL7kiKBYSJG6 zgTLgKiUNKBh>!8!p+pEvGdtt)&U^E0x3`xwTHn52&vpc3pHp&sDN2sX!UJ-^fLm7c zlGmaXoV{QmKwdMD$QSa1EG4LOHW_@Ovuq+_URQH(y2>>n4r>Q!!!(s{uMs83WZ^M6 zWF-ey3gB~IN>qzM0syrZ6b~sL;AoM-5Jqbb*;>v;IfgMo=5hS$FBSoh!m@3h@8bQV zqoaq~*bcq!s_7+mQ`a;&O`NtHasS^!RNbn@o`2%38&hLcz0avpT{WgdIGyk~0-Twp z?IzNXiM~%-#=)#Y3unYB)BV3%$6RZge`%58U9I0OjZOVh2H0W)*i0)7p00q!oi|v! z_jsDx#Ows1kGxE^-Dl2OG|i@%yB4dH3!fPY#Czg6qf4)pEuN`DMZVeD{(-usIn8zcGf4m>E?0N~LWsYi+_x3MlniX3y@g z9)e^1^br~$2^Az^f(o``i3ffWSPlq_9z;dI2#Z0nCjt>(Gts;DRy5fc5pwoT|KpAf znfp@bb(%>9=J{lD^nxp>(+apqTj07)m&*ok*vc$YZFi8?f>#)W33__nG*Y$Z*<><# ziQ$#}0=&($b7(VJ*O0m3cGCdgg(Z94xyx??_xpNyTgkZNRdSh^mZFd3C<(M+SSv>! z%4H?uwov0c8!U4u#o1_RBJTX0n*qlf#kvIC?{j{!PD|GsA^{E50_rRWt?*Te8BEI- z)Tzy)Jm)yY{_<7*9yTTvMOv?-{9^F-ALc^DX|Y zLFpJO>;uX&-#~l<`n;7*JWtEKdio)4Eck>9XR?Z&0&xwOZqt!=&P!OtTcP8-S&32d zS3I?qZxwgSb?-KAHp&jC9UFasCL+vZ)c@;;j52ya{Xfw^cViTqen&PI3nxb>!J}K} lxSPrGu6Om&HfgipwcG8UpwC3FJK^6@L^?$CfJOAs`wxeT{R;p9 literal 0 HcmV?d00001 diff --git a/osinaweb/support/migrations/__pycache__/0008_alter_tickettask_ticket.cpython-310.pyc b/osinaweb/support/migrations/__pycache__/0008_alter_tickettask_ticket.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..459208e0ca806257ca30b2efc0be9c037fe22a2d GIT binary patch literal 754 zcmY*X&5qMB5VoD4reTW^Li|V^xaN}d1RN0BYM12zEQg9qE>>DktE5hxja{wE2?;pv zgYXVKiBCwJcm*W1jFT?ASn{X&#-16^=TVbMOmKZ?UspdUAwM0txqKvtxOIvkh@g_x zG^aJo8FidVFZW*);R*i>5kAl=`0V9@U~`fLzc7X*%*J)O?g~??M%%Df0;E1&y0e>W zgyayneu@Ajr-I~6&^66H@GHzHJP4~1MAf(otGK!)d=XqQ5ngzB=Rl0GVr0kfu1aCu zk>0kg>P-H4I-Ne_g*4D{Q!Y1Pv?*3A-eVpQE>q}@4F~(-QL}N|53-nb?T;e$H*oIo{h!K>L96vuz>WUB?8p&_BeimGVV$}+LAQU4MY)Q*m3^P}1ED;uj8_9A~H-2;s7;rFNP zgN9CLP?r)w%5n$UG3bp^Z8k4tSwDGOw2r*jrCF*vQ@U)5tbz017>W+gb68}1U9#&h z%~0Iu|B36A-0PgSyUxv!`(1q(AtKE4Fa3Z~M(~*t)^$-ti^kR_xB~CTbA;KLN(fi(CV?fy} literal 0 HcmV?d00001 diff --git a/osinaweb/support/models.py b/osinaweb/support/models.py index ca042a9b..6ccdb3bb 100644 --- a/osinaweb/support/models.py +++ b/osinaweb/support/models.py @@ -9,6 +9,7 @@ from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver from threading import Timer +from datetime import time def send_ticket(ticket_id): ticket = get_object_or_404(Ticket, id=ticket_id) @@ -74,10 +75,6 @@ def send_update(update_id): - - - - # Create your models here. class Ticket(models.Model): @@ -109,6 +106,30 @@ class Ticket(models.Model): super().save(*args, **kwargs) + def get_customer_last_seen(self): + connections = TicketConnection.objects.filter(user=self.customer.user).order_by('-date') + if not connections.exists(): + return "Not seen yet" + + last_connection = connections.first() + + if not last_connection.terminated: + return "Online" + + last_seen_time = last_connection.date + now = timezone.now() + time_diff = now - last_seen_time + + if time_diff < timedelta(days=1): + if last_seen_time.date() == now.date(): + return f"last seen today at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen yesterday at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" + + + @receiver(post_save, sender=Ticket) def send_signal_on_save(sender, instance, created, **kwargs): @@ -127,9 +148,32 @@ class TicketDepartment(models.Model): class TicketStaff(models.Model): - staff = models.ForeignKey(StaffPosition, on_delete=models.CASCADE) + staff = models.ForeignKey(StaffProfile, on_delete=models.CASCADE) ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) date_added = models.DateTimeField() + def get_last_seen(self): + connections = TicketConnection.objects.filter(user=self.staff.user).order_by('-date') + if not connections.exists(): + return "Not seen yet" + + last_connection = connections.first() + + if not last_connection.terminated: + return "Online" + + last_seen_time = last_connection.date + now = timezone.now() + time_diff = now - last_seen_time + + if time_diff < timedelta(days=1): + if last_seen_time.date() == now.date(): + return f"last seen today at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen yesterday at {last_seen_time.strftime('%I:%M %p')}" + else: + return f"last seen on {last_seen_time.strftime('%b %d at %I:%M %p')}" + + class TicketStatus(models.Model): STATUS_CHOICES = ( @@ -143,6 +187,20 @@ class TicketStatus(models.Model): date_added = models.DateTimeField() +class TicketTask(models.Model): + ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) + task = models.ForeignKey(Task, on_delete=models.CASCADE) + + + +class TicketConnection(models.Model): + ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) + user = models.ForeignKey(User, on_delete=models.CASCADE) + date = models.DateTimeField() + terminated = models.BooleanField(default=False) + + + class TicketUpdate(models.Model): ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) description = models.TextField(null=True, blank=True) @@ -180,19 +238,3 @@ class TicketUpdateReaction(models.Model): reaction = models.CharField(max_length=50, choices=REACTION_CHOICES, null=True) ticket_update = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE) - -class TicketTask(models.Model): - ticket = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE) - task = models.ForeignKey(Task, on_delete=models.CASCADE) - - - -class TicketConnection(models.Model): - CONNECTION_CHOICES = ( - ('Online', 'Online'), - ('Offline', 'Offline'), - ) - ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE) - user = models.ForeignKey(User, on_delete=models.CASCADE) - type = models.CharField(max_length=50, choices=CONNECTION_CHOICES, null=True) - date = models.DateTimeField() \ No newline at end of file diff --git a/osinaweb/support/templates/details_templates/ticket-room.html b/osinaweb/support/templates/details_templates/ticket-room.html index 20e4e734..3d5bdd88 100644 --- a/osinaweb/support/templates/details_templates/ticket-room.html +++ b/osinaweb/support/templates/details_templates/ticket-room.html @@ -26,20 +26,23 @@
- - - + + {% if request.user.staffprofile %} + + + + {% endif %}
@@ -65,39 +53,66 @@ diff --git a/osinaweb/support/urls.py b/osinaweb/support/urls.py index c54e2b47..d6d9e493 100644 --- a/osinaweb/support/urls.py +++ b/osinaweb/support/urls.py @@ -21,7 +21,7 @@ from django.conf import settings urlpatterns = [ path('tickets//', views.ticket_room, name='ticketroom'), - path('ticket-settings', views.ticket_settings, name='ticketsettings'), + path('tickets//settings/', views.ticket_settings, name='ticketsettings'), path('add-ticket-department', views.add_ticket_department_modal, name='addticketdepartmentmodal'), path('add-ticket-member', views.add_ticket_member_modal, name='addticketmembermodal'), diff --git a/osinaweb/support/views.py b/osinaweb/support/views.py index f8f7c86b..19b0911c 100644 --- a/osinaweb/support/views.py +++ b/osinaweb/support/views.py @@ -1,10 +1,7 @@ from django.shortcuts import render, get_object_or_404 from .models import * from .decorators import * -from django.core.mail import send_mail -from django.template.loader import render_to_string -from django.utils.html import strip_tags -from django.conf import settings +from osinacore.decorators import * # Create your views here. @ticket_member_required @@ -37,10 +34,44 @@ def ticket_room(request, ticket_number): -@ticket_member_required -def ticket_settings(request): + +def get_last_seen_order_key(member): + last_seen_text = member.get_last_seen() + + if last_seen_text == "Online": + return (0, datetime.max) + elif "last seen today" in last_seen_text: + time_part = last_seen_text.split(" at ")[-1] + last_seen_time = datetime.strptime(time_part, '%I:%M %p') + return (1, last_seen_time) + elif "last seen yesterday" in last_seen_text: + time_part = last_seen_text.split(" at ")[-1] + last_seen_time = datetime.now() - timedelta(days=1) + last_seen_time = last_seen_time.replace(hour=datetime.strptime(time_part, '%I:%M %p').hour, + minute=datetime.strptime(time_part, '%I:%M %p').minute) + return (2, last_seen_time) + elif "last seen on" in last_seen_text: + date_time_part = last_seen_text.split(" on ")[-1] + last_seen_time = datetime.strptime(date_time_part, '%b %d at %I:%M %p') + return (3, last_seen_time) + else: + return (4, datetime.min) + + + +@staff_login_required +def ticket_settings(request, ticket_number): + ticket = get_object_or_404(Ticket, ticket_number=ticket_number) + ticket_departments = TicketDepartment.objects.filter(ticket=ticket).order_by('-id') + ticket_members = TicketStaff.objects.filter(ticket=ticket) + ticket_members = sorted(ticket_members, key=get_last_seen_order_key) + customer_last_seen = ticket.get_customer_last_seen() context = { + 'ticket': ticket, + 'ticket_departments': ticket_departments, + 'ticket_members': ticket_members, + 'customer_last_seen': customer_last_seen, }