From 71108fe3ec83d62f99fb385898086d1ca49686db Mon Sep 17 00:00:00 2001 From: nataly Date: Wed, 22 May 2024 16:57:34 +0300 Subject: [PATCH] new changes. --- .../add/__pycache__/urls.cpython-312.pyc | Bin 1070 -> 1070 bytes .../add/__pycache__/views.cpython-312.pyc | Bin 8335 -> 12211 bytes .../__pycache__/models.cpython-312.pyc | Bin 5657 -> 6046 bytes .../__pycache__/urls.cpython-312.pyc | Bin 2647 -> 2244 bytes .../__pycache__/views.cpython-312.pyc | Bin 19584 -> 11194 bytes .../add/__pycache__/urls.cpython-312.pyc | Bin 0 -> 784 bytes .../add/__pycache__/views.cpython-312.pyc | Bin 0 -> 8419 bytes osinaweb/customercore/add/urls.py | 11 + osinaweb/customercore/add/views.py | 175 ++++++++++++++++ osinaweb/customercore/edit/urls.py | 0 osinaweb/customercore/edit/views.py | 0 .../migrations/0017_tickettask.py | 23 ++ .../0017_tickettask.cpython-312.pyc | Bin 0 -> 1395 bytes osinaweb/customercore/models.py | 8 +- .../cutomer-add-ticket-task.html | 0 osinaweb/customercore/urls.py | 7 +- osinaweb/customercore/views.py | 196 +----------------- osinaweb/db.sqlite3 | Bin 1323008 -> 1335296 bytes .../__pycache__/models.cpython-312.pyc | Bin 23840 -> 23840 bytes .../add/__pycache__/views.cpython-312.pyc | Bin 28303 -> 28266 bytes osinaweb/osinacore/add/views.py | 59 +++--- .../osinacore/templates/add-edit-main.html | 96 ++++++--- .../templates/add_templates/add-task.html | 6 + .../templates/add_templates/add-ticket.html | 29 ++- .../details_templates/ticket-details.html | 125 ++++++++++- .../templates/epic-fetched-tasks.html | 10 +- osinaweb/osinacore/templates/index.html | 127 ++++++++++-- .../templates/listing_pages/tasks.html | 32 +-- .../templates/project-open-tasks.html | 10 +- osinaweb/static/dist/output.css | 16 ++ osinaweb/static/images/image_11.pdf | Bin 0 -> 36285 bytes osinaweb/static/images/image_14.pdf | Bin 0 -> 53078 bytes osinaweb/static/js/uploader-bar.js | 80 +++++++ 33 files changed, 699 insertions(+), 311 deletions(-) create mode 100644 osinaweb/customercore/add/__pycache__/urls.cpython-312.pyc create mode 100644 osinaweb/customercore/add/__pycache__/views.cpython-312.pyc create mode 100644 osinaweb/customercore/add/urls.py create mode 100644 osinaweb/customercore/add/views.py create mode 100644 osinaweb/customercore/edit/urls.py create mode 100644 osinaweb/customercore/edit/views.py create mode 100644 osinaweb/customercore/migrations/0017_tickettask.py create mode 100644 osinaweb/customercore/migrations/__pycache__/0017_tickettask.cpython-312.pyc create mode 100644 osinaweb/customercore/templates/add_templates/cutomer-add-ticket-task.html create mode 100644 osinaweb/static/images/image_11.pdf create mode 100644 osinaweb/static/images/image_14.pdf create mode 100644 osinaweb/static/js/uploader-bar.js diff --git a/osinaweb/billing/add/__pycache__/urls.cpython-312.pyc b/osinaweb/billing/add/__pycache__/urls.cpython-312.pyc index 806d987580c3d30baea17f2ef653799a48eeeb2f..60df04cc5ad3b7a194abb0d3981e99ecb712bdc9 100644 GIT binary patch delta 40 tcmZ3-v5tfHG%qg~0}xDq>6*dHI@;!hT+h6dd@^6&J6e`P zhHRQ54T8pYFM-`ALHw(5U=?s7WM_c>@ZV#zU+uW&YBkyo*LJ;}6BwZ}=8p$X2jb1A zn+=TEBG_MLZlfyD=^*qSb^TW8JL~#w&~K{iw?p4m*YAM7yRP2}eNSEA+a-8kWlnbs zKH%FHtzo~~Zpb%|3E#%3RwL;T1B$b!gP)#K(_gIE2~d|+26 z3TjH4Q&Pk@r!1yKP7*dv>9qX9G62f1mET#uGUYtb)I4cfBpf#@5n169d|V{n&CA)M zX<12voHXM=oe4O-VMZjEq^KBfAnlvxk>PJ@lMaxDjRXzW8r2^Apr;G9x{+-|#;TmX zIkz2~)Qk|e%*c9>^&+z%GXV>`$PR4pMAnClMq)R%Hp1c1?Z;?PqjsUfWnw z%d+aI*BR`Gw&vgkfrI#6)|k8C_WBjTF|}k={g0>5_XKL#lei{_ zSBQkw5pS@W2BHxIL5Ik3P&>AA#(NgRu=0_w%aEh@Vh^siAK3w5VMpDmO`!BJGJ4ST z5GS#F1ej))`AcHuP{*JjwpI>x8Wm7L&@M8H>=-cF3JeYjh)~l4>T`i+%L$M!sHwm_ z81?tSF+&f%K6u0F%h4=SoS(z^*F{h}}WG;Z({ zWM`0_1O`v#EVfZ;saMUnbf}9R-W-kRb2w1nv-6Vsyh`|@S$oZIMF(% znkr6>;WE@Fy79Ldrg_xH&K*zCt>~j^f+_SkbXGYQFW#6`C5l`;Dey581B`FnXE~{=YypFsx?ft{?z1$Ut1t+&X~!Bf@ec1W1eqOPrLfO zrrH|jHW-<2Q$K6y922bA(TB1Yp&?^>hY?H}i(p=Yk$0H)%vo!~T9w=0Gi9x{&6#z1{4b_SmrGjfiI%gEz%bwfSv&cFHZ>C|s1+_L41j7eT zHz|0mlrm1;h^!0d;G3-{+DQxUU=&Pdlrl~su-sfT#x1mD+(K|K zjAh(2Ot|$pg{m*U`ugjyHACbJybKQv0|bpqh{$-`2DPKs1VhR!ST7@hjh-@smW{UMCa zCKF0zmXC_;OEn=5R^@Riwzwz9_C1qKrKE)1H@ZnlCeb}?n#6YXrFi8$rzE*lMUTVj z0N62cNKt0{!mu2P^UAJ1g``D<{l4%h%MSOmr&8z$tDF~ET!K}Sw2jkQoX++S+u2;z z+H7s}TH{<&So|K#Hw+(SWj-NC04Sx|>ejNzR^6iBqK$NO$f*($Ss@usV}51(b6~@F zn*d(CkW3R+ye!Fzl$c|oC}L%0F(%5?`sz$jdr}Zs*aI?+G`py)@G_eaML`sFl6fd4%t8%-IPt*Er&2K~N_B@p4m&!d5OJ7KYqAI1c}3x)=h6F7IEGwI z#HwpwD89&nIxZD@;2*Edh#ZvUR8p33<8W&QQYY|=n!pLorbuydDVY$fK)NXML~A%w zxttr=pqXR5tY{{%nq0ui78xv5D#g?!zCY544AT(7Y_2sf5GVl99D*egaiGwI-5L~z zJzD?+yi5~;=ORo|NCONa}cl&hGl3mfz)HvPHL(oA#U8{;ZRr`e;j zTy2w|qir_4&KO3`0akL=cxyH|w^TAAi!#Ele$DjX3QpzR2vqu6qK{WV_pk6LzX6Xq z S-W6}z?mBnpCqDPLymk3{=2}L5xg6{-2K!6?fm=`A8ZY=q^3!Yn_Ui|(9Vq*E z7X3R*{#|8%r09>7{KNU_zcu*Ry0_mPEQj_LL;K31@nUHFMgo@SK9_wUH-M^uIp#6ol#$0Z(!Uz?lES!HGlZNlks#GIuDlI z6Zy$icgu~OrQqt$A71sfUmw0Ue6z3Q>(5WETb({z{^$(vw`9k@rRkP!@sh>@i&4Hr%NZ{)8H(ml2bKtJ|F>u7wd1JgVbl|Rg3=G_P zBtKbb3Kh*gs}6tuY4Y6#!Cs@9a?Tmd>PN0F^+RWKPB1N-b%>b98@z=Syy}z$%WZ@R zpk=Gx5*iTbFB@c|fe~y_B^c-NDQuyvC1c5$m+S!E0P6F2%XFf+3LQXo{B)xvY+$vm zPP&2hi1D>jM4tsfOe+B0w5&bT_-$GlW5$%R3eIHe5g6|=yc_|2cDF~-{N#Hn1PNZWo`r#WkXm%y3Ko-U!@@tqvah=4WwN!`I zIUTI4HRw0N8a@W-PPVFsta*qS=cNRo1INdc>4dU0v{#TWRnTM~;P9LnIR|CIg~&M( z08QM(^05VeQ6BBvzjqiE_mc$LlSG!g2>c`=*uI2p0ofulEEL1;jciU{L@BN14?;_8 z)%{3<~T$CpOAm};yC8}>u+2j?J(PWJuDv+IXSn-iDWauSPfkAe} zcvgIaEV{AeTd0ETY92im>iJjm=v918;?#98DQixBoc5Zc$@n?=5_D*;5%FLEvz%lqG7`LZ-((7GJXks z$_S#P#wjBtDQ`>JyQApckw3Z`+)K zaD``oS_ts@W1BK?{I0#XY#%DxhkhUf4_7nreIL{FgLyQ}s&99%=Ije1FE6H`CQ>N+ z(_5qkWQCud1|ByA?!9anG6d)n F{|8~x*Pj3Y delta 1573 zcmZWpO>7fa5YF0O$I1FP@lXCq^FzFDos>#IqmrZ$5>&_!KLL@TYUSE%SY*dxb{(1? z;!EkJhk{-?AP$@(jy}M(>aCU9YxPud012s=N|k!zP<3WDgmqZSpWe*-=DnG3=DBJ7 za60;HB+}W2-}Aetq(dJkc$65eHNk{PXqikFccfM*l?>Z0 z5k5grt~sa8DoU=o8=mm5k|Mg|mOAOKNrg3Ck@17O49niES1MeE41HC%txeOmWuR1W zOx^DWAIB&-A^wdmDtYl)d~W7rbjZ+|eKN}=gQ$puec<}T6w#`VR9B&d`y=96{G*v! zB6zhqMh-4|j#i%|NbPMpq{s}Zx(1a756Y)>+9`q=1YPs=Zl1gg1l)dZTK3q-s?QH%b2k7hDofy0~&! z)5R~A7OqI`VqvFhZaQoDieQCK2@$Zq?T2U2d*pa#SjmdT%#eBw1HKbh=Dv~>yW!qu zcTdQEdwZ5-I0|RG~BEvj2`}MiC(GW{Nw%Ai;#I2G$zzK2|lw}w^X^Q+nZkjcmz%4t1 z;5KI;-5w=qe70OkjVk321!O*M-XFM%VS4&Xz4dpSV};$;Xr{RV-R5kB649w7?4p65^7<%!7JAhcAZ!5BCp(xnhj;!>o(S1 z;dN_pn`|d2#^2}y(GAk*r^!26MKqEzcXFkuELRCogb`#)X{f)nNrwSGeSgHGeKye zC}RpoDoYmF9GF%Jox-_>Yc(^HI&Ppk9#l0TUJ4JII$oeUJ~VapAccHr3i*Kw1<(|N z)Cr)e69lRg!lF(HO`R}Mod_0nB5SznQG6l_R49f;p%|Kh;y`s0Sky_Nsgne%lft4- z3a+l60UXrQK!q|`6w1IALe$9u)yZK|Cx@m^9;i+Mi#i1~b&B;sg-TcyDxoP<2C7rR zqD}=(ohneB8WweG2zBX#Q6iPjuaops+90~$ASvWexCW>E> kG`K8ic$vj$@?8$S$tIkolaFwAaGOf=Gc|G-X#tf30Cdu5!TicwI!}G%qg~0}yO-_eqmrXJB{?;=q77l<`@Bd7_4sMk-4dSS?H%LZ`5=;aJTK zVKXtLGNy1&TqkbHg(k=i)Xayf5yVU3K~u*&@t?RQADSRPP_qyg%>roZ1Sk73idzby zi3$UCi(%0%f~HP%@;sn!F*H$epl&HFx+T!mNltzT)GdW3Dh<>vhefvxnmXCZc1+@y za%iIRK;24MbSt2#Q=Ht#BwnwCCaMh7t%gOn3Yt1qpgIjK>eSHGsRPw%VNs_6QD*{@ z0w(}Xph6ui3bhahrVB@jS88kOOn$)RHQAjxAcZ?IB}Km^GdVl8ME{mxa%pi%er{?J zP!J+kr3DkxM<^^UNJ%V7)wjvaE3twoi_c84)4wGSQw!G)Q8{@U^NAEEG{K_O#N?99 z{5*Y|;*ugO7%#r0vLMwC*=UFn5DVmSSOC+#IhMtUkx^pu1XgDQVVK%@pvCbJXWo*+ zA{Y;Kz3yLe(ZAvY1A_xoBGVTJ2G%5| T$vPap-1Z9mOpV+{20)_$d06TK diff --git a/osinaweb/customercore/__pycache__/views.cpython-312.pyc b/osinaweb/customercore/__pycache__/views.cpython-312.pyc index ecbe78f148104d449d6670bd22e861b4ad864c6a..99fd72b9fcc92a64aaa18a338269e8df085abd3e 100644 GIT binary patch delta 2467 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 diff --git a/osinaweb/customercore/add/__pycache__/urls.cpython-312.pyc b/osinaweb/customercore/add/__pycache__/urls.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b5f3c52b5dd7c40c6c8d051278ef8a7791702aae GIT binary patch literal 784 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 H<=}q+9||_Y literal 0 HcmV?d00001 diff --git a/osinaweb/customercore/add/urls.py b/osinaweb/customercore/add/urls.py new file mode 100644 index 00000000..9a6df5fb --- /dev/null +++ b/osinaweb/customercore/add/urls.py @@ -0,0 +1,11 @@ +from django.urls import path, include +from . import views + + +urlpatterns = [ + # ADD + path('ticket/', views.customer_add_ticket, name='customeraddticket'), + path('customer/ticketupdate//', views.customer_add_ticket_update, name='customeraddticketupdate'), + path('ticketupdatereaction///', views.customer_add_ticket_update_reaction, name='customeraddticketupdatereaction'), + +] \ No newline at end of file diff --git a/osinaweb/customercore/add/views.py b/osinaweb/customercore/add/views.py new file mode 100644 index 00000000..c4bee3ee --- /dev/null +++ b/osinaweb/customercore/add/views.py @@ -0,0 +1,175 @@ +from django.shortcuts import render, get_object_or_404 +from customercore.decorators import * +from customercore.models 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 + + +@customer_login_required +def customer_add_ticket(request, *args, **kwargs): + customer_orders = Order.objects.filter(customer=request.user.customerprofile) + customer_orders_with_last_status = customer_orders.annotate(max_status_date=Max('orderstatus__date')) + customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed',orderstatus__date=F('max_status_date')) + customer_products = OrderItem.objects.filter(active__in=[True, None], item__type = 'Product', order__customer = request.user.customerprofile, order__in=customer_orders_completed ) + customer_projects = Project.objects.filter(customer=request.user.customerprofile) + support_department = get_object_or_404(Department, name='Support') + + if request.method == 'POST': + project = None + product = None + departments = [support_department] + regarding = 'General/Account/Billing' + if request.POST.get('project') and request.POST.get('regarding') == 'Project': + project = get_object_or_404(Project, id=request.POST.get('project')) + project_types = project.project_type.all() + departments = [project_type.department for project_type in project_types] + regarding = 'Project/Product' + elif request.POST.get('product') and request.POST.get('regarding') == 'Product': + product = get_object_or_404(Item, id=request.POST.get('product')) + departments = [product.item_type.department] + regarding = 'Project/Product' + ticket = Ticket( + status = 'Open', + customer = request.user.customerprofile, + title = request.POST.get('title'), + description = request.POST.get('description'), + regarding = regarding, + project = project, + product = product, + opened_by = request.user, + opened_date = datetime.now() + ) + ticket.save() + ticket.departments.set(departments) + + ticket_status = TicketStatus( + ticket = ticket, + status = 'Open', + added_by = request.user, + date_added = datetime.now() + ) + ticket_status.save() + for file in request.FILES.getlist('files'): + ticket_attachment = TicketAttachment( + ticket=ticket, + file=file + ) + ticket_attachment.save() + + + department_ids = [dept.id for dept in departments] + staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True) + print(staff_profiles) + for staff in staff_profiles: + subject = f"New Ticket Opened: {ticket.title}" + html_message = render_to_string('email_templates/new_ticket.html', { + 'ticket': ticket, + 'staff_first_name': staff.user.first_name + }) + plain_message = strip_tags(html_message) + from_email = settings.DEFAULT_FROM_EMAIL + to_email = staff.user.email + + send_mail(subject, plain_message, from_email, [to_email], html_message=html_message) + return redirect('customerticketdetails', ticket_number=ticket.ticket_number) + + context = { + 'customer_products': customer_products, + 'customer_projects': customer_projects, + + } + + return render(request, 'add_templates/customer-add-ticket.html', context) + + + +@customer_login_required +def customer_add_ticket_update(request, ticket_id): + ticket = get_object_or_404(Ticket, id=ticket_id) + + + if request.method == 'POST': + ticket_update = TicketUpdate( + ticket = ticket, + description = request.POST.get('description'), + added_by = request.user, + date_added = datetime.now(), + ) + ticket_update.save() + for file in request.FILES.getlist('files'): + ticket_attachment = TicketAttachment( + ticket_update=ticket_update, + file=file + ) + ticket_attachment.save() + + + if ticket.ticket_members.exists(): + members_ids = ticket.ticket_members.values_list('id', flat=True) + staff_profiles = StaffProfile.objects.filter(id__in=members_ids) + else: + department_ids = ticket.departments.values_list('id', flat=True) + staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True) + + + for staff in staff_profiles: + subject = f"New Ticket Update: {ticket.title}" + html_message = render_to_string('email_templates/new_ticket_update.html', { + 'ticket_update': ticket_update, + 'staff_first_name': staff.user.first_name + }) + plain_message = strip_tags(html_message) + from_email = settings.DEFAULT_FROM_EMAIL + to_email = staff.user.email + + send_mail(subject, plain_message, from_email, [to_email], html_message=html_message) + + + return redirect('customerticketdetails', ticket_number=ticket.ticket_number) + + context = { + 'ticket': ticket, + } + + return render(request, 'add_templates/customer-add-ticket.html', context) + + + +@customer_login_required +def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id): + ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id) + + existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first() + + if existing_reaction: + # If the existing reaction type is equal to the new reaction, delete it + if existing_reaction.reaction == reaction_type: + existing_reaction.delete() + else: + # If not, delete all previous reactions and add a new one + TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete() + reaction = TicketUpdateReaction.objects.create( + ticket_update=ticket_update, + reaction=reaction_type, + customer=request.user + ) + else: + # If there's no existing reaction, simply add the new one + reaction = TicketUpdateReaction.objects.create( + ticket_update=ticket_update, + reaction=reaction_type, + customer=request.user + ) + + return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number) + + + + + + + + + diff --git a/osinaweb/customercore/edit/urls.py b/osinaweb/customercore/edit/urls.py new file mode 100644 index 00000000..e69de29b diff --git a/osinaweb/customercore/edit/views.py b/osinaweb/customercore/edit/views.py new file mode 100644 index 00000000..e69de29b diff --git a/osinaweb/customercore/migrations/0017_tickettask.py b/osinaweb/customercore/migrations/0017_tickettask.py new file mode 100644 index 00000000..904ba4bf --- /dev/null +++ b/osinaweb/customercore/migrations/0017_tickettask.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.4 on 2024-05-22 12:17 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('customercore', '0016_rename_ticketstatusupdate_ticketstatus'), + ('osinacore', '0081_status_task'), + ] + + operations = [ + migrations.CreateModel( + name='TicketTask', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='osinacore.task')), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customercore.ticketupdate')), + ], + ), + ] diff --git a/osinaweb/customercore/migrations/__pycache__/0017_tickettask.cpython-312.pyc b/osinaweb/customercore/migrations/__pycache__/0017_tickettask.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a89c9609aec99e4e70832b3145a5549decc3993e GIT binary patch literal 1395 zcmcgs%Wu<27#~04#BQ2(P$3&tfRM^+6G~DJAso<3-M)5#MwKX4$qE@KGmV`35p1X6 zok6Z{D)?ZuWVxthzac2C?Q6)v2Z8P}vM?U}LU@Au8)_dRF+oSaku z8T0?FZe0`r_?If_$eeE#{wrFZJZrfp92QbPdR%)l_@<&_c{QyEDNepS^nAxcZr5=UzBV^^d%o@uz2N}r{(q;)VcGEvTW2TLxw%_6v}Cj9>)tk2*4g=Wig^RBFJu1a z#fpgY`p|c@u8RmE#1jM8uyi-jwo!m(54nbJ8oLPRcaYn0Jfu-qut*tq3t!CDsLmX) zHPTPWN0|2=EF~`Qmd^%NOD2;D$Qh9_N?Qgpq1UPua86@JGz}}7M*4GTB7*ap_GGA= zEE7b7Xn<^p?5=@4m-acHSYRQn(uQ_vm*M=6MsJ=3w@j(AvP?2+^z6GNFbVc`yXRmY zc5se4Ol||tF3jIwm|tANiZei`H{^G4Lfht(Q-45`;nhjVe%G<;i%xfFA=~%rE#246 zfG*hj^@O)>qo+(iRT+MYI`y-8sE@B|H_8L~@~=vqyAY#5 literal 0 HcmV?d00001 diff --git a/osinaweb/customercore/models.py b/osinaweb/customercore/models.py index 63e4ea4a..848343ce 100644 --- a/osinaweb/customercore/models.py +++ b/osinaweb/customercore/models.py @@ -79,4 +79,10 @@ class TicketUpdateReaction(models.Model): ) customer = models.ForeignKey(User, on_delete=models.CASCADE, null=True) reaction = models.CharField(max_length=50, choices=REACTION_CHOICES, null=True) - ticket_update = models.ForeignKey(TicketUpdate, on_delete=models.CASCADE) \ No newline at end of file + 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) \ No newline at end of file diff --git a/osinaweb/customercore/templates/add_templates/cutomer-add-ticket-task.html b/osinaweb/customercore/templates/add_templates/cutomer-add-ticket-task.html new file mode 100644 index 00000000..e69de29b diff --git a/osinaweb/customercore/urls.py b/osinaweb/customercore/urls.py index 80c27439..290267c5 100644 --- a/osinaweb/customercore/urls.py +++ b/osinaweb/customercore/urls.py @@ -4,15 +4,11 @@ from . import views urlpatterns = [ path('payment/', include('customercore.payment.urls')), + path('add/', include('customercore.add.urls')), path('redirect-osimenu/', views.redirect_osimenu, name='redirectosimenu'), path('redirect-osicard/', views.redirect_osicard, name='redirectosicard'), - # ADD - path('add/ticket/', views.customer_add_ticket, name='customeraddticket'), - path('customer/add/ticketupdate//', views.customer_add_ticket_update, name='customeraddticketupdate'), - - # LISTING path('my-invoices/', views.customer_invoices, name='customerinvoices'), path('products/', views.all_products, name='products'), @@ -23,7 +19,6 @@ urlpatterns = [ # DETAILS path('my-tickets//', views.customer_ticket_details, name='customerticketdetails'), - path('addticketupdatereaction///', views.customer_add_ticket_update_reaction, name='customeraddticketupdatereaction'), path('my-orders//', views.customer_order_details, name='customerorderdetails'), path('my-projects//', views.customer_project_details, name='customerprojectdetails'), diff --git a/osinaweb/customercore/views.py b/osinaweb/customercore/views.py index 516a813a..179f8c19 100644 --- a/osinaweb/customercore/views.py +++ b/osinaweb/customercore/views.py @@ -6,10 +6,7 @@ from .models import * from django.db.models import Q from django.http import Http404 from django.db.models import OuterRef, Subquery -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 + # Create your views here. @@ -29,168 +26,6 @@ def redirect_osicard(request): return redirect(url) - -# ADD -@customer_login_required -def customer_add_ticket(request, *args, **kwargs): - customer_orders = Order.objects.filter(customer=request.user.customerprofile) - customer_orders_with_last_status = customer_orders.annotate(max_status_date=Max('orderstatus__date')) - customer_orders_completed = customer_orders_with_last_status.filter(orderstatus__status='Completed',orderstatus__date=F('max_status_date')) - customer_products = OrderItem.objects.filter(active__in=[True, None], item__type = 'Product', order__customer = request.user.customerprofile, order__in=customer_orders_completed ) - customer_projects = Project.objects.filter(customer=request.user.customerprofile) - support_department = get_object_or_404(Department, name='Support') - - if request.method == 'POST': - project = None - product = None - departments = [support_department] - regarding = 'General/Account/Billing' - if request.POST.get('project') and request.POST.get('regarding') == 'Project': - project = get_object_or_404(Project, id=request.POST.get('project')) - departments = [project.project_type.department] - regarding = 'Project/Product' - elif request.POST.get('product') and request.POST.get('regarding') == 'Product': - product = get_object_or_404(Item, id=request.POST.get('product')) - departments = [product.item_type.department] - regarding = 'Project/Product' - ticket = Ticket( - status = 'Open', - customer = request.user.customerprofile, - title = request.POST.get('title'), - description = request.POST.get('description'), - regarding = regarding, - project = project, - product = product, - opened_by = request.user, - opened_date = datetime.now() - ) - ticket.save() - ticket.departments.set(departments) - - ticket_status = TicketStatus( - ticket = ticket, - status = 'Open', - added_by = request.user, - date_added = datetime.now() - ) - ticket_status.save() - for file in request.FILES.getlist('files'): - ticket_attachment = TicketAttachment( - ticket=ticket, - file=file - ) - ticket_attachment.save() - - - department_ids = [dept.id for dept in departments] - staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True) - print(staff_profiles) - for staff in staff_profiles: - subject = f"New Ticket Opened: {ticket.title}" - html_message = render_to_string('email_templates/new_ticket.html', { - 'ticket': ticket, - 'staff_first_name': staff.user.first_name - }) - plain_message = strip_tags(html_message) - from_email = settings.DEFAULT_FROM_EMAIL - to_email = staff.user.email - - send_mail(subject, plain_message, from_email, [to_email], html_message=html_message) - return redirect('customerticketdetails', ticket_number=ticket.ticket_number) - - context = { - 'customer_products': customer_products, - 'customer_projects': customer_projects, - - } - - return render(request, 'add_templates/customer-add-ticket.html', context) - - - -@customer_login_required -def customer_add_ticket_update(request, ticket_id): - ticket = get_object_or_404(Ticket, id=ticket_id) - - - if request.method == 'POST': - ticket_update = TicketUpdate( - ticket = ticket, - description = request.POST.get('description'), - added_by = request.user, - date_added = datetime.now(), - ) - ticket_update.save() - for file in request.FILES.getlist('files'): - ticket_attachment = TicketAttachment( - ticket_update=ticket_update, - file=file - ) - ticket_attachment.save() - - - if ticket.ticket_members.exists(): - members_ids = ticket.ticket_members.values_list('id', flat=True) - staff_profiles = StaffProfile.objects.filter(id__in=members_ids) - else: - department_ids = ticket.departments.values_list('id', flat=True) - staff_profiles = StaffProfile.objects.filter(staff_position__department__id__in=department_ids, active=True) - - - for staff in staff_profiles: - subject = f"New Ticket Update: {ticket.title}" - html_message = render_to_string('email_templates/new_ticket_update.html', { - 'ticket_update': ticket_update, - 'staff_first_name': staff.user.first_name - }) - plain_message = strip_tags(html_message) - from_email = settings.DEFAULT_FROM_EMAIL - to_email = staff.user.email - - send_mail(subject, plain_message, from_email, [to_email], html_message=html_message) - - - return redirect('customerticketdetails', ticket_number=ticket.ticket_number) - - context = { - 'ticket': ticket, - } - - return render(request, 'add_templates/customer-add-ticket.html', context) - - - -@customer_login_required -def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id): - ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id) - - existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first() - - if existing_reaction: - # If the existing reaction type is equal to the new reaction, delete it - if existing_reaction.reaction == reaction_type: - existing_reaction.delete() - else: - # If not, delete all previous reactions and add a new one - TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete() - reaction = TicketUpdateReaction.objects.create( - ticket_update=ticket_update, - reaction=reaction_type, - customer=request.user - ) - else: - # If there's no existing reaction, simply add the new one - reaction = TicketUpdateReaction.objects.create( - ticket_update=ticket_update, - reaction=reaction_type, - customer=request.user - ) - - return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number) - - - - # LISTING @customer_login_required def customer_invoices(request, *args, **kwargs): @@ -356,35 +191,6 @@ def customer_ticket_details(request, ticket_number): return render(request, 'details_templates/inner-customer-ticket.html', context) -@customer_login_required -def customer_add_ticket_update_reaction(request, reaction_type, ticketupdate_id): - ticket_update = get_object_or_404(TicketUpdate, id=ticketupdate_id) - - existing_reaction = TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).first() - - if existing_reaction: - # If the existing reaction type is equal to the new reaction, delete it - if existing_reaction.reaction == reaction_type: - existing_reaction.delete() - else: - # If not, delete all previous reactions and add a new one - TicketUpdateReaction.objects.filter(ticket_update=ticket_update, customer=request.user).delete() - reaction = TicketUpdateReaction.objects.create( - ticket_update=ticket_update, - reaction=reaction_type, - customer=request.user - ) - else: - # If there's no existing reaction, simply add the new one - reaction = TicketUpdateReaction.objects.create( - ticket_update=ticket_update, - reaction=reaction_type, - customer=request.user - ) - - return redirect('customerticketdetails', ticket_number=ticket_update.ticket.ticket_number) - - # PRODUCTS diff --git a/osinaweb/db.sqlite3 b/osinaweb/db.sqlite3 index fd6347e1d62df01b30e97885ad7219c98f7fadc7..a830643ddb63f73296bc82cc7a611ea8ee58951f 100644 GIT binary patch delta 4119 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 diff --git a/osinaweb/osinacore/__pycache__/models.cpython-312.pyc b/osinaweb/osinacore/__pycache__/models.cpython-312.pyc index 2e75911815f0cda55cdd7ec9408438c768d6ca2c..2ada3c16f5f62ca9000404709610d2acdb774d88 100644 GIT binary patch delta 22 ccmZ3mi*dm&M()$Ryj%=G;C*3QMb)^Toi(y7ppW@~AsmaPK~t&C1%g>@6CWCc^K-;#8aPm0BMSqikK*%Nc0II(Wzr9V+_to;&qQ$*608B z{ogO2-@g1a^;?y){9v&d0lu~#zA<&{8_TsxA`3HtYf1u9QBd8}m5S>}%E zO!TeKXp?)DW?KN1E&xz99v~e^vhx|Pk#LpnMkfFyC#0YDF(*vu*EmmTFG?NyG|&QB zXoO(;Ii0lkRC;uKI)aj{*H+;3Y$KH8AU7RFDjR6wruQQ|C_1T+h9ASAtU*(8FCKguwDg$6o8I=OT(W4;ZAh#z1v(7`(dim zmXQ*P%p8KrF^WasCA+B|bU!&t?V_RgOKlJr$!^q<>h{WnATMI5m``U?=hDiAl2jJ5 z@+mZ)@|m8HEYS!%(LySI@n7NteEtpIhs52%P~oKXd{S0s({oB9BV{YDYZd#9^^U{&mK8D)>EK=h%9t~1&(#7C0Y=z#Ui-tf|2$hAf zDul~IpDOg-J-sn__eAkbyf}XWlSb({T@?CowI_idN{5cu+PTjbKVAHiFSU!BgI{WI zfG4=-zv?f0qN*o)bGGCeS>mck2Bt|$(d#PK5I*IdyhwuU}R_qJ(5 z_|jMnZKQiIVsmM1%kI{k9<3vwIXtVqE4^h$m+I)cK2&ldeYaRS1%bueb+JqrsYN-iJUl^;+F^n{*4KI$&ug;Z*xI znv|2Hi7=H6L2*WQmFOa41oNEY%sarD^x%XDBLd5)V=$ULXu4ukEqk6jEg?474R_g& zzyX7y88MqH?^u{M`8@98LwR+y=^~Mb7ZK%0`6d;6vr6B-Dq5eZtO$rP72%J79omx; zxxQO8)sX|S2=l^9KyqmPW@ByuQmo%q>MSy6nPu^S-5NM81$I>qf|14+1s_}9OIDhPLX&TXX?$?CI+mKBInfhOV{We0kG30&gpay=TtW@#E63GCLG?mVS*X zcfW+K@DzNl_{HhtWewr{I5WqTy@znZmxgU+80u5($c8nf3sS*q04FRb786x2P~ie! zOm1?~ny`=$?=+1};xtoUDqGiWvEFdP5ulI@dAd4eOFj ze!d>v8(MR$I%@s{Yq8bXl_z&QIl*4A)V&njzRWFhOMESKkdP6+uFL2ms`>kf*QtF~~(7T&b=!1Fm7&drD6J9n!l7bup-Wd)9xPr - -
-

Tickets

-
-
-
@@ -154,15 +147,29 @@
-
-
- - - -

Support

+
-
-
- - - -

Support

+ + +