diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..e7c4d0d --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +SECRET_KEY=django-insecure-change-me-in-production-!@#$%^&*() diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..1960fd8 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,58 @@ +# ServiceCRM Copilot Instructions + +## Project Overview +ServiceCRM is a simple Service Ticket Management System built with Django. It manages repair tickets ("Inserts") for service customers, tracking details like customer info, defect description, repair status, and notes. + +## Architecture +- **Framework**: Django 4.x (compatible with 5.x/6.x in dependencies). +- **Structure**: Single-app project where the `serviceCRM` package contains both project settings and application logic (views, models, urls). +- **Patterns**: Model-View-Template (MVT). +- **Frontend**: Server-side rendered templates using Bootstrap 5 and `django-crispy-forms`. + +## Key Components + +### Data Model +- **Primary Model**: `Insert` (defined in `serviceCRM/models.py`). + - Represents a service ticket. + - Key fields: `name`, `phone`, `description` (defect), `repair` (resolution), `done` (status), `date`. + +### Views & Controllers +- **Location**: `serviceCRM/views.py`. +- **Pattern**: Mix of Class-Based Views (CBV) and Function-Based Views (FBV). + - List views use `django_tables2.SingleTableView`. + - Create/Update use `generic.View` and `generic.UpdateView`. + - **Note**: Some views use a non-standard static method pattern (e.g., `InsertNew.insert` referenced in URLs). + +### UI/UX +- **Tables**: `django-tables2` is used for listing records (`serviceCRM/tables.py`). +- **Forms**: `django-crispy-forms` with `crispy-bootstrap5` pack (`serviceCRM/forms.py`). +- **Templates**: Located in `templates/` and `templates/serviceCRM/`. + +## Configuration & Environment +- **Settings**: `serviceCRM/settings.py` uses `django-environ`. +- **Environment**: Configuration reads from `.env` file (see `.env.example`). +- **Database**: + - Local/Dev: SQLite (configured via `settings.py` overriding env vars if needed). + - Production: Configurable via `DATABASE_URL` or individual env vars (PostgreSQL supported). + +## Development Workflow + +### Setup +1. Create `.env` from `.env.example`. +2. Install dependencies: `pip install -r requirements.txt`. +3. Run migrations: `python manage.py migrate`. + +### Common Commands +- **Run Server**: `python manage.py runserver` +- **Make Migrations**: `python manage.py makemigrations` (Required when changing `models.py`) +- **Migrate**: `python manage.py migrate` + +## Coding Conventions +- **Imports**: standard library -> third party -> django -> local apps. +- **Urls**: Defined in `serviceCRM/urls.py` (which is the root URLconf). +- **Routing**: Routes are mixed between CBV (`.as_view()`) and function references. Maintain consistency with existing patterns when adding new routes. + +## Critical Patterns to Respect +1. **Forms**: Always use `InputForm` in `serviceCRM/forms.py` for ticket creation/editing to ensure consistent widget rendering with Bootstrap classes. +2. **Tables**: When adding lists, subclass `tables.Table` in `serviceCRM/tables.py` and use `SingleTableView` for display/sorting features. +3. **Template Inheritance**: All templates should extend `base.html`. diff --git a/.gitignore b/.gitignore index 287780c..c322c6a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .idea/ # Ignore __pycache__ folders and .pyc files -__pycache__/ +*__pycache__/ *.pyc # Ignore .env files @@ -14,7 +14,9 @@ __pycache__/ # Ignore .DS_Store files .DS_Store -.vscode\ +.vscode + +db.sqlite3 pyvenv.cfg diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..6324d40 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.14 diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 99cf7ae..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Python Debugger: Django", - "type": "debugpy", - "request": "launch", - "program": "${workspaceFolder}\\manage.py", - "args": [ - "runserver" - ], - "django": true, - "autoStartBrowser": false - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index b1eb010..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "cmake.configureOnOpen": false, - "python.pythonPath": ".venv\\Scripts\\python.exe" -} \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..35d8c3b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,38 @@ +# Django Backend Dockerfile +FROM ghcr.io/astral-sh/uv:python3.13-alpine AS builder + +WORKDIR /app + +ENV UV_COMPILE_BYTECODE=1 + +COPY pyproject.toml uv.lock ./ + +RUN uv sync --frozen --no-dev --no-install-project + +COPY serviceCRM/ ./serviceCRM/ +COPY manage.py ./ + +RUN uv sync --frozen --no-dev + + +FROM python:3.13-alpine + +WORKDIR /app + +RUN apk add --no-cache postgresql-client + +COPY --from=builder /app/.venv /app/.venv +COPY --from=builder /app/serviceCRM/ /app/serviceCRM/ +COPY --from=builder /app/manage.py /app/ + +RUN adduser -D -u 1000 appuser && \ + chown -R appuser:appuser /app + +USER appuser + +ENV PATH="/app/.venv/bin:$PATH" +ENV PYTHONUNBUFFERED=1 + +EXPOSE 8000 + +CMD ["python", "-m", "uvicorn", "serviceCRM.asgi:application", "--host", "0.0.0.0", "--port", "8000"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..b81bec6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,14 @@ +version: '3.8' + +services: + web: + build: . + volumes: + - .:/app + ports: + - "8000:8000" + env_file: + - .env + environment: + - DEBUG=False + - ALLOWED_HOSTS=* diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..960dd47 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,35 @@ +[project] +name = "servicecrm" +version = "0.1.0" +description = "A CRM application built with Django." +readme = "README.md" +requires-python = ">=3.14" +dependencies = [ + "asgiref>=3.11.0", + "cffi>=2.0.0", + "crispy-bootstrap5>=2025.6", + "crispy-tailwind>=1.0.3", + "cryptography>=46.0.3", + "django>=6.0.1", + "django-crispy-forms>=2.5", + "django-datatable-view>=2.1.6", + "django-environ>=0.12.0", + "django-filter>=25.2", + "django-pipeline>=4.1.0", + "django-tables2>=2.8.0", + "dnspython>=2.8.0", + "feedparser>=6.0.12", + "nanoid>=2.0.0", + "pillow>=12.1.0", + "publicsuffix>=1.1.1", + "pycparser>=2.23", + "python-dateutil>=2.9.0.post0", + "pytz>=2025.2", + "sgmllib3k>=1.0.0", + "six>=1.17.0", + "sqlparse>=0.5.5", + "tablib>=3.9.0", + "typing-extensions>=4.15.0", + "tzdata>=2025.3", + "uvicorn>=0.40.0", +] diff --git a/requirements.txt b/requirements.txt index b51db47..4aa0eb6 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/serviceCRM/filter.py b/serviceCRM/filter.py index 2bd3373..2ea1fe9 100644 --- a/serviceCRM/filter.py +++ b/serviceCRM/filter.py @@ -1,6 +1,27 @@ from .models import Insert import django_filters as filters from django_filters import FilterSet +from django.db.models import Q +from django import forms + +class InsertFilter(FilterSet): + start_date = filters.DateFilter(field_name="date", lookup_expr='gte', label='Од датум', widget=forms.TextInput(attrs={'type': 'date'})) + end_date = filters.DateFilter(field_name="date", lookup_expr='lte', label='До датум', widget=forms.TextInput(attrs={'type': 'date'})) + search = filters.CharFilter(method='filter_search', label='Пребарај (Име, Тел, ID, Опис)') + + class Meta: + model = Insert + fields = ['search', 'done'] + + def filter_search(self, queryset, name, value): + return queryset.filter( + Q(name__icontains=value) | + Q(phone__icontains=value) | + Q(description__icontains=value) | + Q(plateno__icontains=value) | + Q(ticket_id__icontains=value) | + Q(id__icontains=value) + ) class DoneTable(FilterSet): class Meta: @@ -11,4 +32,22 @@ class DoneTable(FilterSet): if value: return queryset.filter(done=True) else: - return queryset.filter(done=False) \ No newline at end of file + return queryset.filter(done=False) +class DoneFilter(FilterSet): + start_date = filters.DateFilter(field_name="date_close", lookup_expr='gte', label='Од датум (Затворено)', widget=forms.TextInput(attrs={'type': 'date'})) + end_date = filters.DateFilter(field_name="date_close", lookup_expr='lte', label='До датум (Затворено)', widget=forms.TextInput(attrs={'type': 'date'})) + search = filters.CharFilter(method='filter_search', label='Пребарај (Име, Тел, ID)') + + class Meta: + model = Insert + fields = ['status'] + + def filter_search(self, queryset, name, value): + return queryset.filter( + Q(name__icontains=value) | + Q(phone__icontains=value) | + Q(description__icontains=value) | + Q(plateno__icontains=value) | + Q(ticket_id__icontains=value) | + Q(id__icontains=value) + ) diff --git a/serviceCRM/forms.py b/serviceCRM/forms.py index 76a8427..ed8c35f 100644 --- a/serviceCRM/forms.py +++ b/serviceCRM/forms.py @@ -1,4 +1,5 @@ from django import forms +from django.utils.translation import gettext_lazy as _ from .models import Insert @@ -9,17 +10,31 @@ class DateInput(forms.DateInput): class InputForm(forms.ModelForm): class Meta: model = Insert - fields = {"name", "phone", "description", "date", "note"} - labels = {'name': "Name", 'phone': "Phone", 'date': "Date", 'description': "Description", 'note': "Note"} + fields = ["name", "phone", "date", "description", "note"] + labels = { + 'name': "Име", + 'phone': "Телефон", + 'date': "Датум на прием", + 'description': "Опис на проблем", + 'note': "Забелешка" + } widgets = { - 'name': forms.TextInput(attrs={'class': 'form-control'}), - 'phone': forms.TextInput(attrs={'class': 'form-control'}), 'date': DateInput(), - 'description': forms.Textarea(attrs={'class': 'form-control'}), - 'note': forms.TextInput(attrs={'class': 'form-control'}) + 'description': forms.Textarea(attrs={'rows': 3}), } - field_order = ["name", "phone", "date", "description", "done"] +class CloseForm(forms.ModelForm): + class Meta: + model = Insert + fields = ["repair", "plateno"] + labels = { + 'repair': "Детали за поправка", + 'plateno': "Наплатено" + } + widgets = { + 'repair': forms.Textarea(attrs={'rows': 4}), + 'plateno': forms.TextInput(attrs={'placeholder': 'пр. 1500 МКД'}) + } # class EditForm(forms.ModelForm): # class Meta: diff --git a/serviceCRM/migrations/0006_insert_date_close.py b/serviceCRM/migrations/0006_insert_date_close.py new file mode 100644 index 0000000..ad850d6 --- /dev/null +++ b/serviceCRM/migrations/0006_insert_date_close.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.1 on 2026-01-08 11:09 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0005_alter_insert_done'), + ] + + operations = [ + migrations.AddField( + model_name='insert', + name='date_close', + field=models.DateField(blank=True, null=True, verbose_name='date closed'), + ), + ] diff --git a/serviceCRM/migrations/0007_insert_status.py b/serviceCRM/migrations/0007_insert_status.py new file mode 100644 index 0000000..d96ea6f --- /dev/null +++ b/serviceCRM/migrations/0007_insert_status.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.1 on 2026-01-08 11:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0006_insert_date_close'), + ] + + operations = [ + migrations.AddField( + model_name='insert', + name='status', + field=models.CharField(choices=[('RECEIVED', 'Received'), ('DIAGNOSING', 'Diagnosing'), ('WAITING_PARTS', 'Waiting for Parts'), ('READY', 'Ready for Pickup'), ('COMPLETED', 'Completed')], default='RECEIVED', max_length=20), + ), + ] diff --git a/serviceCRM/migrations/0008_insert_ticket_id.py b/serviceCRM/migrations/0008_insert_ticket_id.py new file mode 100644 index 0000000..0f7adbf --- /dev/null +++ b/serviceCRM/migrations/0008_insert_ticket_id.py @@ -0,0 +1,19 @@ +# Generated by Django 6.0.1 on 2026-01-08 11:30 + +import serviceCRM.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0007_insert_status'), + ] + + operations = [ + migrations.AddField( + model_name='insert', + name='ticket_id', + field=models.CharField(default=serviceCRM.models.generate_nanoid, max_length=12, null=True), + ), + ] diff --git a/serviceCRM/migrations/0009_alter_insert_ticket_id.py b/serviceCRM/migrations/0009_alter_insert_ticket_id.py new file mode 100644 index 0000000..f0ba1b2 --- /dev/null +++ b/serviceCRM/migrations/0009_alter_insert_ticket_id.py @@ -0,0 +1,19 @@ +# Generated by Django 6.0.1 on 2026-01-08 11:32 + +import serviceCRM.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0008_insert_ticket_id'), + ] + + operations = [ + migrations.AlterField( + model_name='insert', + name='ticket_id', + field=models.CharField(default=serviceCRM.models.generate_nanoid, editable=False, max_length=12, unique=True), + ), + ] diff --git a/serviceCRM/migrations/0010_ticketlog.py b/serviceCRM/migrations/0010_ticketlog.py new file mode 100644 index 0000000..49b1f95 --- /dev/null +++ b/serviceCRM/migrations/0010_ticketlog.py @@ -0,0 +1,27 @@ +# Generated by Django 6.0.1 on 2026-01-08 13:04 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0009_alter_insert_ticket_id'), + ] + + operations = [ + migrations.CreateModel( + name='TicketLog', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('timestamp', models.DateTimeField(auto_now_add=True)), + ('action', models.CharField(max_length=50)), + ('details', models.TextField(blank=True, null=True)), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='logs', to='serviceCRM.insert')), + ], + options={ + 'ordering': ['-timestamp'], + }, + ), + ] diff --git a/serviceCRM/migrations/0011_alter_insert_date_alter_insert_date_close_and_more.py b/serviceCRM/migrations/0011_alter_insert_date_alter_insert_date_close_and_more.py new file mode 100644 index 0000000..ae4f021 --- /dev/null +++ b/serviceCRM/migrations/0011_alter_insert_date_alter_insert_date_close_and_more.py @@ -0,0 +1,63 @@ +# Generated by Django 6.0.1 on 2026-01-08 14:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('serviceCRM', '0010_ticketlog'), + ] + + operations = [ + migrations.AlterField( + model_name='insert', + name='date', + field=models.DateField(verbose_name='Датум'), + ), + migrations.AlterField( + model_name='insert', + name='date_close', + field=models.DateField(blank=True, null=True, verbose_name='Датум затворање'), + ), + migrations.AlterField( + model_name='insert', + name='description', + field=models.CharField(max_length=300, verbose_name='Опис'), + ), + migrations.AlterField( + model_name='insert', + name='done', + field=models.BooleanField(default=False, verbose_name='Завршено'), + ), + migrations.AlterField( + model_name='insert', + name='name', + field=models.CharField(max_length=50, verbose_name='Име'), + ), + migrations.AlterField( + model_name='insert', + name='note', + field=models.CharField(blank=True, default=None, max_length=100, null=True, verbose_name='Забелешка'), + ), + migrations.AlterField( + model_name='insert', + name='phone', + field=models.CharField(max_length=20, verbose_name='Телефон'), + ), + migrations.AlterField( + model_name='insert', + name='plateno', + field=models.CharField(blank=True, default=None, max_length=10, null=True, verbose_name='Плаќање/Рег.'), + ), + migrations.AlterField( + model_name='insert', + name='repair', + field=models.CharField(blank=True, default=None, max_length=300, null=True, verbose_name='Поправка'), + ), + migrations.AlterField( + model_name='insert', + name='status', + field=models.CharField(choices=[('RECEIVED', 'Примено'), ('DIAGNOSING', 'Дијагностика'), ('WAITING_PARTS', 'Чека делови'), ('READY', 'Готово за подигање'), ('COMPLETED', 'Завршено')], default='RECEIVED', max_length=20, verbose_name='Статус'), + ), + ] diff --git a/serviceCRM/models.py b/serviceCRM/models.py index d615e72..731ce2c 100644 --- a/serviceCRM/models.py +++ b/serviceCRM/models.py @@ -1,19 +1,63 @@ from django.db import models from django.contrib.auth.models import UserManager +from nanoid import generate +def generate_nanoid(): + return generate(size=12) class Insert(models.Model): - name = models.CharField(max_length=50) - phone = models.CharField(max_length=20) - description = models.CharField(max_length=300) - note= models.CharField(max_length=100, default=None, blank=True, null=True) - date = models.DateField("date submitted") - done = models.BooleanField(default=False) - repair = models.CharField(default=None, blank=True, null=True,max_length=300) - plateno = models.CharField(max_length=10, default=None, blank=True, null=True) + ticket_id = models.CharField(max_length=12, default=generate_nanoid, unique=True, editable=False) + name = models.CharField(max_length=50, verbose_name="Име") + phone = models.CharField(max_length=20, verbose_name="Телефон") + description = models.CharField(max_length=300, verbose_name="Опис") + note= models.CharField(max_length=100, default=None, blank=True, null=True, verbose_name="Забелешка") + date = models.DateField("Датум") + done = models.BooleanField(default=False, verbose_name="Завршено") + + STATUS_CHOICES = [ + ('RECEIVED', 'Примено'), + ('DIAGNOSING', 'Дијагностика'), + ('WAITING_PARTS', 'Чека делови'), + ('READY', 'Готово за подигање'), + ('COMPLETED', 'Завршено'), + ] + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='RECEIVED', verbose_name="Статус") + + date_close = models.DateField("Датум затворање", null=True, blank=True) + repair = models.CharField(default=None, blank=True, null=True,max_length=300, verbose_name="Поправка") + plateno = models.CharField(max_length=10, default=None, blank=True, null=True, verbose_name="Плаќање/Рег.") + + def save(self, *args, **kwargs): + from django.utils import timezone + + # Sync done and status fields + if self.status == 'COMPLETED': + self.done = True + if not self.date_close: + self.date_close = timezone.now().date() + elif self.done: + self.status = 'COMPLETED' + if not self.date_close: + self.date_close = timezone.now().date() + else: + self.done = False + + super(Insert, self).save(*args, **kwargs) def __str__(self): return "Ime: " + self.name + " Telefonski broj: " + self.phone + "\nDefekt: " + self.description + "\nDatum: \n" def isDone(self): return self.done + +class TicketLog(models.Model): + ticket = models.ForeignKey(Insert, on_delete=models.CASCADE, related_name='logs') + timestamp = models.DateTimeField(auto_now_add=True) + action = models.CharField(max_length=50) + details = models.TextField(blank=True, null=True) + + class Meta: + ordering = ['-timestamp'] + + def __str__(self): + return f"{self.ticket.ticket_id} - {self.action} at {self.timestamp}" diff --git a/serviceCRM/settings.py b/serviceCRM/settings.py index 1d319a5..f6c684b 100644 --- a/serviceCRM/settings.py +++ b/serviceCRM/settings.py @@ -25,9 +25,9 @@ BASE_DIR = Path(__file__).resolve().parent.parent SECRET_KEY = env('SECRET_KEY') # SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True +DEBUG = env.bool('DEBUG', default=False) -ALLOWED_HOSTS = ['*'] +ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=['*']) # Application definition @@ -39,22 +39,29 @@ INSTALLED_APPS = [ 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', + 'whitenoise.runserver_nostatic', # Add whitenoise before staticfiles 'django.contrib.staticfiles', 'crispy_forms', - 'crispy_bootstrap5', + 'crispy_tailwind', 'django_tables2', + 'django_filters', ] -CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5" -CRISPY_TEMPLATE_PACK = "bootstrap5" +CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind" +CRISPY_TEMPLATE_PACK = "tailwind" DJANGO_TABLES2_TABLE_ATTRS = { - 'class': 'table table-hover', + 'class': 'min-w-full divide-y divide-gray-200 border', 'thead': { - 'class': 'table-light', + 'class': 'bg-gray-50', + }, + 'tbody': { + 'class': 'bg-white divide-y divide-gray-200', }, } MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', + 'whitenoise.middleware.WhiteNoiseMiddleware', # Add whitenoise middleware 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.locale.LocaleMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -88,12 +95,8 @@ WSGI_APPLICATION = 'serviceCRM.wsgi.application' DATABASES = { 'default': { - 'ENGINE': 'django.db.backends.postgresql', - 'NAME': env('DATABASE_NAME'), - 'USER': env('DATABASE_USER'), - 'PASSWORD': env('DATABASE_PASS'), - 'HOST': env('DATABASE_HOST'), - 'PORT': env('DATABASE_PORT'), + 'ENGINE': 'django.db.backends.sqlite3', + 'NAME': BASE_DIR / 'db.sqlite3', } } @@ -120,9 +123,20 @@ AUTH_PASSWORD_VALIDATORS = [ # Internationalization # https://docs.djangoproject.com/en/4.2/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = 'mk' -TIME_ZONE = 'UTC' +from django.utils.translation import gettext_lazy as _ + +LANGUAGES = [ + ('mk', _('Macedonian')), + ('en', _('English')), +] + +LOCALE_PATHS = [ + BASE_DIR / 'locale', +] + +TIME_ZONE = 'Europe/Skopje' USE_I18N = True @@ -133,8 +147,13 @@ USE_TZ = True # https://docs.djangoproject.com/en/4.2/howto/static-files/ STATIC_URL = 'static/' +STATIC_ROOT = BASE_DIR / 'staticfiles' +STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' # Default primary key field type # https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +LOGIN_REDIRECT_URL = '/' +LOGIN_URL = '/admin/login/' diff --git a/serviceCRM/tables.py b/serviceCRM/tables.py index c5ce725..01f8e2e 100644 --- a/serviceCRM/tables.py +++ b/serviceCRM/tables.py @@ -6,18 +6,24 @@ from .models import Insert class InsertTable(tables.Table): - actions = TemplateColumn(template_code='Edit Details') + actions = TemplateColumn(template_code=''' + Види + Уреди + {% if not record.done %} + Затвори + {% endif %} + ''') class Meta: model = Insert - fields = ("id","name","phone","description","date","done") + fields = ("ticket_id","name","phone","description","date","status","done") per_page = 5 class DoneInsertTable(InsertTable): class Meta: model = Insert - fields = ("id","name","phone","description","date","done") + fields = ("ticket_id","name","phone","description","date", "date_close", "done") per_page = 5 def __init__(self, *args, **kwargs): diff --git a/serviceCRM/templates/base.html b/serviceCRM/templates/base.html index 91e6f22..d29999c 100644 --- a/serviceCRM/templates/base.html +++ b/serviceCRM/templates/base.html @@ -1,43 +1,92 @@ - -
- - - -