diff --git a/serviceCRM/forms.py b/serviceCRM/forms.py
index ed8c35f..101f322 100644
--- a/serviceCRM/forms.py
+++ b/serviceCRM/forms.py
@@ -1,11 +1,14 @@
from django import forms
from django.utils.translation import gettext_lazy as _
-from .models import Insert
+from .models import Insert, Todo
class DateInput(forms.DateInput):
input_type = 'date'
+class TimeInput(forms.TimeInput):
+ input_type = 'time'
+
class InputForm(forms.ModelForm):
class Meta:
@@ -19,7 +22,7 @@ class InputForm(forms.ModelForm):
'note': "Забелешка"
}
widgets = {
- 'date': DateInput(),
+ 'date': DateInput(format='%Y-%m-%d'),
'description': forms.Textarea(attrs={'rows': 3}),
}
@@ -36,7 +39,38 @@ class CloseForm(forms.ModelForm):
'plateno': forms.TextInput(attrs={'placeholder': 'пр. 1500 МКД'})
}
+class TodoForm(forms.ModelForm):
+ class Meta:
+ model = Todo
+ fields = ['title', 'name', 'phone', 'scheduled_date', 'scheduled_time']
+ widgets = {
+ 'title': forms.TextInput(attrs={
+ 'class': 'form-control',
+ 'placeholder': 'Опис на задача...',
+ }),
+ 'name': forms.TextInput(attrs={
+ 'class': 'form-control',
+ 'placeholder': 'Име на лице...'
+ }),
+ 'phone': forms.TextInput(attrs={
+ 'class': 'form-control',
+ 'placeholder': '070-xxx-xxx'
+ }),
+ 'scheduled_date': DateInput(format='%Y-%m-%d'),
+ 'scheduled_time': TimeInput(format='%H:%M', attrs={
+ 'class': 'form-control'
+ })
+ }
+ labels = {
+ 'title': 'Задача',
+ 'name': 'Име',
+ 'phone': 'Телефон',
+ 'scheduled_date': 'Датум',
+ 'scheduled_time': 'Време'
+ }
+
# class EditForm(forms.ModelForm):
+
# class Meta:
# model = Insert
# fields = {"name", "phone", "description", "done"}
diff --git a/serviceCRM/migrations/0012_todo.py b/serviceCRM/migrations/0012_todo.py
new file mode 100644
index 0000000..8fb5083
--- /dev/null
+++ b/serviceCRM/migrations/0012_todo.py
@@ -0,0 +1,25 @@
+# Generated by Django 6.0.1 on 2026-01-27 19:59
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('serviceCRM', '0011_alter_insert_date_alter_insert_date_close_and_more'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Todo',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200, verbose_name='Task')),
+ ('is_completed', models.BooleanField(default=False)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ],
+ options={
+ 'ordering': ['is_completed', '-created_at'],
+ },
+ ),
+ ]
diff --git a/serviceCRM/migrations/0013_alter_todo_options_todo_name_todo_phone_and_more.py b/serviceCRM/migrations/0013_alter_todo_options_todo_name_todo_phone_and_more.py
new file mode 100644
index 0000000..839db8e
--- /dev/null
+++ b/serviceCRM/migrations/0013_alter_todo_options_todo_name_todo_phone_and_more.py
@@ -0,0 +1,37 @@
+# Generated by Django 6.0.1 on 2026-01-27 20:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('serviceCRM', '0012_todo'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='todo',
+ options={'ordering': ['is_completed', 'scheduled_date', 'scheduled_time', '-created_at']},
+ ),
+ migrations.AddField(
+ model_name='todo',
+ name='name',
+ field=models.CharField(blank=True, max_length=100, null=True, verbose_name='Име'),
+ ),
+ migrations.AddField(
+ model_name='todo',
+ name='phone',
+ field=models.CharField(blank=True, max_length=20, null=True, verbose_name='Телефон'),
+ ),
+ migrations.AddField(
+ model_name='todo',
+ name='scheduled_date',
+ field=models.DateField(blank=True, null=True, verbose_name='Датум'),
+ ),
+ migrations.AddField(
+ model_name='todo',
+ name='scheduled_time',
+ field=models.TimeField(blank=True, null=True, verbose_name='Време'),
+ ),
+ ]
diff --git a/serviceCRM/models.py b/serviceCRM/models.py
index 731ce2c..be51436 100644
--- a/serviceCRM/models.py
+++ b/serviceCRM/models.py
@@ -50,6 +50,21 @@ class Insert(models.Model):
def isDone(self):
return self.done
+class Todo(models.Model):
+ title = models.CharField(max_length=200, verbose_name="Task")
+ name = models.CharField(max_length=100, verbose_name="Име", blank=True, null=True)
+ phone = models.CharField(max_length=20, verbose_name="Телефон", blank=True, null=True)
+ scheduled_date = models.DateField(verbose_name="Датум", blank=True, null=True)
+ scheduled_time = models.TimeField(verbose_name="Време", blank=True, null=True)
+ is_completed = models.BooleanField(default=False)
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return self.title
+
+ class Meta:
+ ordering = ['is_completed', 'scheduled_date', 'scheduled_time', '-created_at']
+
class TicketLog(models.Model):
ticket = models.ForeignKey(Insert, on_delete=models.CASCADE, related_name='logs')
timestamp = models.DateTimeField(auto_now_add=True)
diff --git a/serviceCRM/tables.py b/serviceCRM/tables.py
index 01f8e2e..1b169e4 100644
--- a/serviceCRM/tables.py
+++ b/serviceCRM/tables.py
@@ -7,12 +7,24 @@ from .models import Insert
class InsertTable(tables.Table):
actions = TemplateColumn(template_code='''
- Види
- Уреди
- {% if not record.done %}
- Затвори
- {% endif %}
- ''')
+
+ ''', orderable=False)
+
+ phone = TemplateColumn(template_code='''
+
+
+ {{ record.phone }}
+ Повикај
+
+ ''', orderable=False)
class Meta:
model = Insert
diff --git a/serviceCRM/templates/base.html b/serviceCRM/templates/base.html
index d29999c..8e4f54c 100644
--- a/serviceCRM/templates/base.html
+++ b/serviceCRM/templates/base.html
@@ -33,7 +33,7 @@
- Активни налози
+ Активни
Архива
+
+
+ Задачи
+
{% endif %}
- Проверка на статус
+ Статус
-
+
{% if user.is_authenticated %}
-
+
Нов Налог
-
-
Здраво, {{ user.username }}
+
{% endif %}
+
+
+
+
+
+
+
diff --git a/serviceCRM/templates/serviceCRM/nalog.html b/serviceCRM/templates/serviceCRM/nalog.html
index 9d911ba..15c3f0a 100644
--- a/serviceCRM/templates/serviceCRM/nalog.html
+++ b/serviceCRM/templates/serviceCRM/nalog.html
@@ -2,10 +2,10 @@
{% load static %}
{% block content %}
-
-
+
+
Сервисен Налог #{{ data.ticket_id }}
-
Креиран на {{ data.date }} (Интерен ID: {{ data.id }})
+
Креиран на {{ data.date|date:"d/m/y" }} (Интерен ID: {{ data.id }})
Датум на затворање
- {{ data.date_close }}
+ {{ data.date_close|date:"d/m/y" }}
{% endif %}
diff --git a/serviceCRM/templates/serviceCRM/print_label.html b/serviceCRM/templates/serviceCRM/print_label.html
index 5e0dac0..cd26df7 100644
--- a/serviceCRM/templates/serviceCRM/print_label.html
+++ b/serviceCRM/templates/serviceCRM/print_label.html
@@ -25,7 +25,7 @@
-
{{ ticket.date }}
+
{{ ticket.date|date:"d/m/y" }}
#{{ ticket.id }}
{{ ticket.ticket_id }}
diff --git a/serviceCRM/templates/serviceCRM/print_receipt.html b/serviceCRM/templates/serviceCRM/print_receipt.html
index 2a02bf7..4102629 100644
--- a/serviceCRM/templates/serviceCRM/print_receipt.html
+++ b/serviceCRM/templates/serviceCRM/print_receipt.html
@@ -81,7 +81,7 @@
Налог #{{ ticket.id }}
Реф: {{ ticket.ticket_id }}
-
{{ ticket.date }}
+
{{ ticket.date|date:"d/m/y" }}
{{ ticket.get_status_display }}
@@ -138,7 +138,7 @@
Налог #{{ ticket.id }}
Реф: {{ ticket.ticket_id }}
-
{{ ticket.date }}
+
{{ ticket.date|date:"d/m/y" }}
{{ ticket.get_status_display }}
diff --git a/serviceCRM/templates/serviceCRM/public_track_result.html b/serviceCRM/templates/serviceCRM/public_track_result.html
index c1a8f2d..0431bd8 100644
--- a/serviceCRM/templates/serviceCRM/public_track_result.html
+++ b/serviceCRM/templates/serviceCRM/public_track_result.html
@@ -7,13 +7,15 @@
{% if ticket.done %}
✓ ЗАВРШЕНО
+ {% elif ticket.status == 'READY' %}
+ ✓ ГОТОВО ЗА ПОДИГАЊЕ
{% else %}
⟳ ВО ИЗРАБОТКА
{% endif %}
@@ -63,7 +65,7 @@
Датум на прием
- {{ ticket.date }}
+ {{ ticket.date|date:"d/m/y" }}
@@ -82,7 +84,7 @@
Завршено на
- {{ ticket.date_close }}
+ {{ ticket.date_close|date:"d/m/y" }}
{% endif %}
diff --git a/serviceCRM/templates/serviceCRM/todo_edit.html b/serviceCRM/templates/serviceCRM/todo_edit.html
new file mode 100644
index 0000000..a485d45
--- /dev/null
+++ b/serviceCRM/templates/serviceCRM/todo_edit.html
@@ -0,0 +1,91 @@
+{% extends 'base.html' %}
+{% load crispy_forms_tags %}
+
+{% block content %}
+
+
+
+
+{% endblock %}
diff --git a/serviceCRM/templates/serviceCRM/todo_list.html b/serviceCRM/templates/serviceCRM/todo_list.html
new file mode 100644
index 0000000..287abb8
--- /dev/null
+++ b/serviceCRM/templates/serviceCRM/todo_list.html
@@ -0,0 +1,267 @@
+{% extends 'base.html' %}
+{% load crispy_forms_tags %}
+
+{% block content %}
+
+
+
+
+
+
+
Задачи
+
Управувајте со вашите дневни задачи
+
+
+
{{ completed }}/{{ total }}
+
Завршени
+
+
+ {% if total > 0 %}
+
+
+ Прогрес
+ {{ progress }}%
+
+
+
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {% for todo in todos %}
+ -
+
+
+
+ {% if todo.is_completed %}
+
+ {% else %}
+
+ {% endif %}
+
+
+
+ {{ todo.title }}
+
+ {% if todo.name or todo.phone %}
+
+ {% if todo.name %}
+
+
+ {{ todo.name }}
+
+ {% endif %}
+ {% if todo.phone %}
+
+
+ {{ todo.phone }}
+
+ {% endif %}
+
+ {% endif %}
+
+ {% if todo.scheduled_date %}
+
+
+ {{ todo.scheduled_date|date:"d/m/y" }}
+
+ {% endif %}
+ {% if todo.scheduled_time %}
+
+
+ {{ todo.scheduled_time|time:"H:i" }}
+
+ {% endif %}
+
• Креирано: {{ todo.created_at|date:"d/m/y" }}
+
+
+
+
+
+
+ {% empty %}
+ -
+
+
+
No tasks
+
Get started by creating a new task.
+
+
+ {% endfor %}
+
+
+
+{% endblock %}
diff --git a/serviceCRM/urls.py b/serviceCRM/urls.py
index df379e1..f33cf76 100644
--- a/serviceCRM/urls.py
+++ b/serviceCRM/urls.py
@@ -39,4 +39,10 @@ urlpatterns = [
path("done/", view.Done.as_view(), name="done"),
path("done/
/", view.Done.done_by_id, name="done_detail"),
path("datatable/", view.DatatableView.as_view(), name="datatable"),
+
+ # Todo List
+ path('todo/', view.todo_list, name='todo_list'),
+ path('todo/toggle//', view.todo_toggle, name='todo_toggle'),
+ path('todo/edit//', view.todo_edit, name='todo_edit'),
+ path('todo/delete//', view.todo_delete, name='todo_delete'),
]
diff --git a/serviceCRM/views.py b/serviceCRM/views.py
index e482fa9..8c20553 100644
--- a/serviceCRM/views.py
+++ b/serviceCRM/views.py
@@ -6,8 +6,8 @@ from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
-from .forms import InputForm, CloseForm
-from .models import Insert, TicketLog
+from .forms import InputForm, CloseForm, TodoForm
+from .models import Insert, TicketLog, Todo
from .tables import DoneInsertTable, InsertTable
from .filter import InsertFilter, DoneFilter
@@ -45,7 +45,7 @@ class InsertNew(generic.View):
TicketLog.objects.create(ticket=ticket, action="Креирано", details="Налогот е креиран во системот.")
return HttpResponseRedirect(f"/ticket/{ticket.ticket_id}/")
else:
- form = InputForm()
+ form = InputForm(initial={'date': timezone.localdate()})
return render(request, InsertNew.template_name, {'form': form})
@@ -148,3 +148,86 @@ def home(request):
if request.user.is_authenticated:
return redirect('dashboard')
return track_ticket(request)
+
+@login_required
+def todo_list(request):
+ # Get filter from query parameter (default: 'active' - not done only)
+ filter_type = request.GET.get('filter', 'active')
+
+ # Filter todos based on selection
+ if filter_type == 'completed':
+ todos = Todo.objects.filter(is_completed=True)
+ elif filter_type == 'all':
+ todos = Todo.objects.all()
+ else: # 'active' - default
+ todos = Todo.objects.filter(is_completed=False)
+
+ # Calculate progress for the UI (always based on all tasks)
+ all_todos = Todo.objects.all()
+ total = all_todos.count()
+ completed = all_todos.filter(is_completed=True).count()
+ progress = int((completed / total * 100)) if total > 0 else 0
+
+ form = TodoForm(initial={'scheduled_date': timezone.localdate()})
+ if request.method == 'POST':
+ form = TodoForm(request.POST)
+ if form.is_valid():
+ form.save()
+ return redirect('todo_list')
+
+ context = {
+ 'todos': todos,
+ 'form': form,
+ 'total': total,
+ 'completed': completed,
+ 'progress': progress,
+ 'filter_type': filter_type,
+ 'active_count': all_todos.filter(is_completed=False).count(),
+ }
+ return render(request, 'serviceCRM/todo_list.html', context)
+
+@login_required
+def todo_edit(request, pk):
+ todo = get_object_or_404(Todo, pk=pk)
+ if request.method == 'POST':
+ form = TodoForm(request.POST, instance=todo)
+ if form.is_valid():
+ form.save()
+ return redirect('todo_list')
+ else:
+ form = TodoForm(instance=todo)
+
+ context = {
+ 'form': form,
+ 'todo': todo,
+ 'is_edit': True
+ }
+ return render(request, 'serviceCRM/todo_edit.html', context)
+
+@login_required
+def todo_toggle(request, pk):
+ todo = get_object_or_404(Todo, pk=pk)
+ todo.is_completed = not todo.is_completed
+ todo.save()
+ return redirect('todo_list')
+
+@login_required
+def todo_delete(request, pk):
+ todo = get_object_or_404(Todo, pk=pk)
+ todo.delete()
+ return redirect('todo_list')
+ context = {'todos': todo, 'form': form}
+ return render(request, 'serviceCRM/todo_list.html', context)
+
+@login_required
+def todo_toggle(request, pk):
+ todo = get_object_or_404(Todo, pk=pk)
+ todo.is_completed = not todo.is_completed
+ todo.save()
+ return redirect('todo_list')
+
+@login_required
+def todo_delete(request, pk):
+ todo = get_object_or_404(Todo, pk=pk)
+ todo.delete()
+ return redirect('todo_list')