diff --git a/backend/core/settings/unfold_conf.py b/backend/core/settings/unfold_conf.py
index 23bf662..44f5e63 100644
--- a/backend/core/settings/unfold_conf.py
+++ b/backend/core/settings/unfold_conf.py
@@ -239,6 +239,12 @@ UNFOLD = {
"badge": "utils.admin.new_ticket_count",
},
+ {
+ "title": _("ارتباط با ما"),
+ "icon": "perm_phone_msg",
+ "link": reverse_lazy("admin:ticket_contactusmodel_changelist"),
+ "badge": "utils.admin.new_contact_us_count",
+ },
],
},
{
diff --git a/backend/core/views.py b/backend/core/views.py
index be623df..9894f4e 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -8,7 +8,7 @@ from django.utils.translation import gettext_lazy as _
from django.views.generic import RedirectView, TemplateView
from unfold.views import UnfoldModelAdminViewMixin
from order.models import OrderModel
-from ticket.models import Ticket
+from ticket.models import Ticket, ContactUsModel
from account.models import SecurityBreachAttemptModel
import json
@@ -19,9 +19,11 @@ def dashboard_callback(request, context):
pending_count = OrderModel.objects.filter(status='ADMIN_PENDING').count()
open_tickets_count = Ticket.objects.filter(status__in=['open', 'in_progress']).count()
+ open_contact_us_count = ContactUsModel.objects.filter(is_reviewed=False).count()
context.update(random_data())
context.update({'pending_count': pending_count})
context.update({'open_tickets_count': open_tickets_count})
+ context.update({'open_contact_us_count': open_contact_us_count})
return context
diff --git a/backend/templates/formula/service.html b/backend/templates/formula/service.html
index 57856a4..ca6cc92 100644
--- a/backend/templates/formula/service.html
+++ b/backend/templates/formula/service.html
@@ -39,4 +39,25 @@
{% endcomponent %}
-{% endif %}
\ No newline at end of file
+{% endif %}
+{% if open_contact_us_count%}
+
+
+
+
+
+ confirmation_number
+ ارتباط با ما جدید داری
+ {{ open_contact_us_count }}
+
+
+
+
+ {% component "unfold/components/flex.html" with class="flex-col gap-4 lg:flex-row" %}
+ {% component "unfold/components/button.html" with href="/secret-admin/ticket/contactusmodel/" %}
+ نمایش ارتباط با ما ها
+ {% endcomponent %}
+ {% endcomponent %}
+
+
+{% endif %}
diff --git a/backend/ticket/admin.py b/backend/ticket/admin.py
index 1426233..bc50d27 100644
--- a/backend/ticket/admin.py
+++ b/backend/ticket/admin.py
@@ -18,6 +18,15 @@ class MessageInline(TabularInline):
model = Message
extra = 1
+@admin.register(ContactUsModel)
+class ContactUsAdmin(ModelAdmin):
+ list_filter = ['type', 'is_reviewed']
+ list_display = ['full_name', 'phone', 'email', 'message', 'is_reviewed']
+ compressed_fields = True
+ warn_unsaved_form = True
+ readonly_fields = ['full_name', 'email', 'phone', 'type', 'message', ]
+
+
@admin.register(Ticket)
class TicketAdmin(ModelAdmin, ImportExportModelAdmin):
import_form_class = ImportForm
diff --git a/backend/ticket/migrations/0020_contactusmodel.py b/backend/ticket/migrations/0020_contactusmodel.py
new file mode 100644
index 0000000..d2bd2be
--- /dev/null
+++ b/backend/ticket/migrations/0020_contactusmodel.py
@@ -0,0 +1,24 @@
+# Generated by Django 5.1.2 on 2025-04-21 22:52
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ticket', '0019_alter_attachment_options'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='ContactUsModel',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('full_name', models.CharField(max_length=50, verbose_name='نام و نام خانوادگی')),
+ ('email', models.EmailField(max_length=254, verbose_name='ایمیل')),
+ ('phone', models.CharField(max_length=30)),
+ ('type', models.CharField(choices=[('ORDER', 'پیگیری سفارش'), ('SUGGESTION', 'پیشنهادات'), ('COMPLAINT', 'انتقادات')], max_length=20, verbose_name='نوع')),
+ ('message', models.TextField(verbose_name='پیام')),
+ ],
+ ),
+ ]
diff --git a/backend/ticket/migrations/0021_alter_contactusmodel_type.py b/backend/ticket/migrations/0021_alter_contactusmodel_type.py
new file mode 100644
index 0000000..59c5790
--- /dev/null
+++ b/backend/ticket/migrations/0021_alter_contactusmodel_type.py
@@ -0,0 +1,18 @@
+# Generated by Django 5.1.2 on 2025-04-21 22:53
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ticket', '0020_contactusmodel'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='contactusmodel',
+ name='type',
+ field=models.CharField(choices=[('ORDER_FOLLOW_UP', 'پیگیری سفارش'), ('SUGGESTION', 'پیشنهادات'), ('COMPLAINT', 'انتقادات')], max_length=20, verbose_name='نوع'),
+ ),
+ ]
diff --git a/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py b/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py
new file mode 100644
index 0000000..537844b
--- /dev/null
+++ b/backend/ticket/migrations/0022_alter_contactusmodel_options_and_more.py
@@ -0,0 +1,22 @@
+# Generated by Django 5.1.2 on 2025-04-21 22:57
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ticket', '0021_alter_contactusmodel_type'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='contactusmodel',
+ options={'verbose_name': 'ارتباط با ما', 'verbose_name_plural': 'ارتباط با ما ها '},
+ ),
+ migrations.AddField(
+ model_name='contactusmodel',
+ name='is_reviewed',
+ field=models.BooleanField(default=False),
+ ),
+ ]
diff --git a/backend/ticket/models.py b/backend/ticket/models.py
index 0941fe3..a6b89a4 100644
--- a/backend/ticket/models.py
+++ b/backend/ticket/models.py
@@ -73,4 +73,26 @@ class Message(models.Model):
class Meta:
verbose_name = 'پیام تیکت'
- verbose_name_plural = 'پیام های تیکت'
\ No newline at end of file
+ verbose_name_plural = 'پیام های تیکت'
+
+
+class ContactUsModel(models.Model):
+ full_name = models.CharField(max_length=50, verbose_name='نام و نام خانوادگی')
+ email = models.EmailField(max_length=254, verbose_name='ایمیل')
+ phone = models.CharField(max_length=30, verbose_name='شماره تماس')
+ FEEDBACK_TYPES = [
+ ('ORDER_FOLLOW_UP', 'پیگیری سفارش'),
+ ('SUGGESTION', 'پیشنهادات'),
+ ('COMPLAINT', 'انتقادات'),
+ ]
+
+ type = models.CharField(max_length=20, choices=FEEDBACK_TYPES, verbose_name='نوع')
+ message = models.TextField(verbose_name='پیام')
+ is_reviewed = models.BooleanField(default=False, verbose_name='بررسی شده')
+
+ def __str__(self):
+ return f'{self.full_name} - {self.message[:15]}...'
+
+ class Meta:
+ verbose_name = 'ارتباط با ما'
+ verbose_name_plural = 'ارتباط با ما ها '
\ No newline at end of file
diff --git a/backend/ticket/serializers.py b/backend/ticket/serializers.py
index d99a8d2..f4af17d 100644
--- a/backend/ticket/serializers.py
+++ b/backend/ticket/serializers.py
@@ -1,5 +1,5 @@
from rest_framework import serializers
-from .models import Ticket, Message, Attachment
+from .models import Ticket, Message, Attachment, ContactUsModel
from django.utils.timezone import localtime
from order.serializers import OrderListSerializer
from order.serializers import OrderModel
@@ -88,4 +88,10 @@ class TicketListSerializer(serializers.ModelSerializer):
return obj.get_status_display()
def get_ticket_category(self, obj):
- return obj.get_ticket_category_display()
\ No newline at end of file
+ return obj.get_ticket_category_display()
+
+
+class ContactUsSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = ContactUsModel
+ fields = ['full_name', 'email', 'phone', 'type', 'message']
\ No newline at end of file
diff --git a/backend/ticket/urls.py b/backend/ticket/urls.py
index c3a47f5..50eed91 100644
--- a/backend/ticket/urls.py
+++ b/backend/ticket/urls.py
@@ -6,6 +6,7 @@ urlpatterns = [
path('', views.TicketListView.as_view(), name='ticket-list'),
path('', views.TicketDetailView.as_view(), name='ticket-detail'),
path('message/create', views.MessageCreateView.as_view(), name='message-create'),
+ path('contact-us/create', views.CreateContactUsView.as_view(), name='contact-us-create'),
path('attachment/create', views.AttachmentUploadView.as_view(), name='attachment-upload'),
path('attachment/delete/', views.AttachmentDeleteView.as_view(), name='attachment-upload'),
]
\ No newline at end of file
diff --git a/backend/ticket/views.py b/backend/ticket/views.py
index ac6fdae..e669864 100644
--- a/backend/ticket/views.py
+++ b/backend/ticket/views.py
@@ -2,7 +2,7 @@ from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import Ticket, Message, Attachment
-from .serializers import TicketListSerializer, MessageSerializer, TicketSerializer, AttachmentSerializer
+from .serializers import TicketListSerializer, MessageSerializer, TicketSerializer, AttachmentSerializer, ContactUsSerializer
from utils.pagination import StructurePagination
from drf_spectacular.utils import extend_schema, OpenApiParameter, OpenApiTypes
from rest_framework.permissions import IsAuthenticated
@@ -56,7 +56,6 @@ class TicketCreateView(APIView):
permission_classes = [permissions.IsAuthenticated]
def post(self, request):
new_ticket_ser = self.serializer_class(data=request.data, context={'request': request})
- message = request.data.get('message', None)
if new_ticket_ser.is_valid():
new_ticket_ser.save(customer=request.user)
return Response(new_ticket_ser.data, status=status.HTTP_201_CREATED)
@@ -159,4 +158,16 @@ class UpdateTicketStatusView(APIView):
return Response({"error": "Invalid status"}, status=400)
ticket.status = new_status
ticket.save()
- return Response({"message": "Ticket status updated successfully"})
\ No newline at end of file
+ return Response({"message": "Ticket status updated successfully"})
+
+
+class CreateContactUsView(APIView):
+ serializer_class = ContactUsSerializer
+ permission_classes = [permissions.AllowAny]
+ def post(self, request):
+ contact_us_ser = self.serializer_class(data=request.data, context={'request': request})
+ if contact_us_ser.is_valid():
+ contact_us_ser.save()
+ return Response(contact_us_ser.data, status=status.HTTP_201_CREATED)
+ else:
+ return Response(contact_us_ser.errors, status=status.HTTP_400_BAD_REQUEST)
\ No newline at end of file
diff --git a/backend/utils/admin.py b/backend/utils/admin.py
index 1107fab..82c4d05 100644
--- a/backend/utils/admin.py
+++ b/backend/utils/admin.py
@@ -1,6 +1,6 @@
from order.models import OrderModel
from product.models import DollorModel, CommentModel
-from ticket.models import Ticket
+from ticket.models import Ticket, ContactUsModel
from home.models import LearnVideoModel
from account.models import SecurityBreachAttemptModel
@@ -24,6 +24,9 @@ def new_learn_video_count(request):
def new_attck_count(request):
return SecurityBreachAttemptModel.objects.filter(viewd=False).count()
+def new_contact_us_count(request):
+ return ContactUsModel.objects.filter(is_reviewed=False).count()
+
from django.contrib import admin, messages
from unfold.admin import ModelAdmin
from home.models import LearnVideoModel