mirror of
https://github.com/ferdzo/serviceCRM.git
synced 2026-04-05 21:16:24 +00:00
Initial commit
This commit is contained in:
22
backend/.gitignore
vendored
Normal file
22
backend/.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# Ignore .idea folder created by PyCharm
|
||||
.idea/
|
||||
|
||||
# Ignore __pycache__ folders and .pyc files
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Ignore .env files
|
||||
*.env
|
||||
|
||||
# Ignore .venv folder
|
||||
.venv/
|
||||
|
||||
# Ignore .DS_Store files
|
||||
.DS_Store
|
||||
|
||||
.vscode\
|
||||
|
||||
pyvenv.cfg
|
||||
|
||||
|
||||
|
||||
2
backend/README.md
Normal file
2
backend/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# serviceCRM
|
||||
Simple CRM for making reports for service customers
|
||||
73
backend/index.html
Normal file
73
backend/index.html
Normal file
@@ -0,0 +1,73 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Servicing Ticket</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header img {
|
||||
max-width: 150px;
|
||||
}
|
||||
.ticket {
|
||||
border: 2px solid #000;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ticket-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ticket-info label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ticket-description {
|
||||
border-top: 2px solid #000;
|
||||
padding-top: 10px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="fer-logo.png" style="max-width:65%" alt="Company Logo">
|
||||
</div>
|
||||
<div class="ticket">
|
||||
<div class="ticket-info">
|
||||
<label>Име и презиме:</label> {{ ticket.name }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Телефонски број:</label> {{ticket.phone}}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Датум:</label> {{ticket.date}}
|
||||
</div>
|
||||
<div class="ticket-description">
|
||||
<label><b>Опис на дефект:</b></label>{% if ticket.description %} {{ ticket.description }} {% else %} Нема опис {% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:150px;"></div>
|
||||
<div class="ticket">
|
||||
<div class="ticket-info">
|
||||
<label>Име и презиме:</label> {{ ticket.name }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Телефонски број:</label> {{ ticket.phone }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Датум:</label> {{ ticket.date }}
|
||||
</div>
|
||||
<div class="ticket-description">
|
||||
<label><b>Опис на дефект:</b></label>{% if ticket.description %} {{ ticket.description }} {% else %} Нема опис {% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
22
backend/manage.py
Normal file
22
backend/manage.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'serviceCRM.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
backend/requirements.txt
Normal file
BIN
backend/requirements.txt
Normal file
Binary file not shown.
0
backend/serviceCRM/__init__.py
Normal file
0
backend/serviceCRM/__init__.py
Normal file
5
backend/serviceCRM/admin.py
Normal file
5
backend/serviceCRM/admin.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import Insert
|
||||
|
||||
admin.site.register(Insert)
|
||||
6
backend/serviceCRM/apps.py
Normal file
6
backend/serviceCRM/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class serviceCRMconfig(AppConfig):
|
||||
name = "serviceCRM"
|
||||
verbose_name = "Service CRM"
|
||||
16
backend/serviceCRM/asgi.py
Normal file
16
backend/serviceCRM/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for serviceCRM project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'serviceCRM.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
14
backend/serviceCRM/filter.py
Normal file
14
backend/serviceCRM/filter.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from .models import Insert
|
||||
import django_filters as filters
|
||||
from django_filters import FilterSet
|
||||
|
||||
class DoneTable(FilterSet):
|
||||
class Meta:
|
||||
model = Insert
|
||||
fields = ["done"]
|
||||
|
||||
def filter_done(self, queryset, name, value):
|
||||
if value:
|
||||
return queryset.filter(done=True)
|
||||
else:
|
||||
return queryset.filter(done=False)
|
||||
35
backend/serviceCRM/forms.py
Normal file
35
backend/serviceCRM/forms.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from django import forms
|
||||
from .models import Insert
|
||||
|
||||
|
||||
class DateInput(forms.DateInput):
|
||||
input_type = 'date'
|
||||
|
||||
|
||||
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"}
|
||||
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'})
|
||||
}
|
||||
|
||||
field_order = ["name", "phone", "date", "description", "done"]
|
||||
|
||||
# class EditForm(forms.ModelForm):
|
||||
# class Meta:
|
||||
# model = Insert
|
||||
# fields = {"name", "phone", "description", "done"}
|
||||
# labels = {'name': "Name", 'phone': "Phone", 'description': "Description", 'done': "Done"}
|
||||
# widgets = {
|
||||
# 'name': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
# 'phone': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
# 'description': forms.Textarea(attrs={'class': 'form-control'})
|
||||
# }
|
||||
|
||||
# field_order = ["name", "phone", "description", "done"]
|
||||
25
backend/serviceCRM/migrations/0001_initial.py
Normal file
25
backend/serviceCRM/migrations/0001_initial.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 4.2 on 2023-04-17 22:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Insert',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=50)),
|
||||
('phone', models.CharField(max_length=20)),
|
||||
('description', models.CharField(max_length=300)),
|
||||
('date', models.DateField(verbose_name='date submitted')),
|
||||
('done', models.BooleanField()),
|
||||
],
|
||||
),
|
||||
]
|
||||
18
backend/serviceCRM/migrations/0002_insert_repair.py
Normal file
18
backend/serviceCRM/migrations/0002_insert_repair.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-19 19:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('serviceCRM', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='insert',
|
||||
name='repair',
|
||||
field=models.CharField(blank=True, default=None, max_length=300, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-19 20:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('serviceCRM', '0002_insert_repair'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='insert',
|
||||
name='note',
|
||||
field=models.CharField(blank=True, default=None, max_length=100, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='insert',
|
||||
name='plateno',
|
||||
field=models.CharField(blank=True, default=None, max_length=10, null=True),
|
||||
),
|
||||
]
|
||||
18
backend/serviceCRM/migrations/0004_alter_insert_done.py
Normal file
18
backend/serviceCRM/migrations/0004_alter_insert_done.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-19 21:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('serviceCRM', '0003_insert_note_insert_plateno'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='insert',
|
||||
name='done',
|
||||
field=models.BooleanField(blank=True, default=None, null=True),
|
||||
),
|
||||
]
|
||||
18
backend/serviceCRM/migrations/0005_alter_insert_done.py
Normal file
18
backend/serviceCRM/migrations/0005_alter_insert_done.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.0.3 on 2024-03-19 21:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('serviceCRM', '0004_alter_insert_done'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='insert',
|
||||
name='done',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
0
backend/serviceCRM/migrations/__init__.py
Normal file
0
backend/serviceCRM/migrations/__init__.py
Normal file
19
backend/serviceCRM/models.py
Normal file
19
backend/serviceCRM/models.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import UserManager
|
||||
|
||||
|
||||
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)
|
||||
|
||||
def __str__(self):
|
||||
return "Ime: " + self.name + " Telefonski broj: " + self.phone + "\nDefekt: " + self.description + "\nDatum: \n"
|
||||
|
||||
def isDone(self):
|
||||
return self.done
|
||||
140
backend/serviceCRM/settings.py
Normal file
140
backend/serviceCRM/settings.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""
|
||||
Django settings for serviceCRM project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 4.2.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/4.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import environ
|
||||
env = environ.Env()
|
||||
environ.Env.read_env('.env')
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/4.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = env('SECRET_KEY')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'serviceCRM.apps.serviceCRMconfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'crispy_forms',
|
||||
'crispy_bootstrap5',
|
||||
'django_tables2',
|
||||
]
|
||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||
CRISPY_TEMPLATE_PACK = "bootstrap5"
|
||||
DJANGO_TABLES2_TABLE_ATTRS = {
|
||||
'class': 'table table-hover',
|
||||
'thead': {
|
||||
'class': 'table-light',
|
||||
},
|
||||
}
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'serviceCRM.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.debug',
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'serviceCRM.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#databases
|
||||
|
||||
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'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/4.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/4.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/4.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
BIN
backend/serviceCRM/static/fer-logo.png
Normal file
BIN
backend/serviceCRM/static/fer-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
25
backend/serviceCRM/tables.py
Normal file
25
backend/serviceCRM/tables.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import django_tables2 as tables
|
||||
from django_tables2 import TemplateColumn
|
||||
from django_filters import FilterSet
|
||||
from django.db.models.query import QuerySet # Add missing import
|
||||
from .models import Insert
|
||||
|
||||
class InsertTable(tables.Table):
|
||||
|
||||
actions = TemplateColumn(template_code='<a class="btn btn-secondary" href="{% url \'update\' record.id %}">Edit</a> <a class="btn btn-secondary" href="{% url \'done\' record.id %}">Details</a>')
|
||||
|
||||
class Meta:
|
||||
model = Insert
|
||||
fields = ("id","name","phone","description","date","done")
|
||||
per_page = 5
|
||||
|
||||
|
||||
class DoneInsertTable(InsertTable):
|
||||
class Meta:
|
||||
model = Insert
|
||||
fields = ("id","name","phone","description","date","done")
|
||||
per_page = 5
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
print(self.data)
|
||||
43
backend/serviceCRM/templates/base.html
Normal file
43
backend/serviceCRM/templates/base.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"/>
|
||||
<title>Service </title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="http://code.jquery.com/jquery-3.3.1.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-datetimepicker/2.5.20/jquery.datetimepicker.full.min.js"></script>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="/">Service CRM</a>
|
||||
</div>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="/insert"><span class="glyphicon glyphicon-user"></span>Insert</a></li>
|
||||
<li><a href="/admin"><span class="glyphicon glyphicon-log-in"></span> Admin</a></li>
|
||||
<li><a href="/done"><span class="glyphicon glyphicon-log-in"></span> Done</a></li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="container">
|
||||
{% comment %} <h1 class="mt-2">Service CRM</h1>
|
||||
<a href='/insert'><button type="button" class="btn btn-dark">Insert</button></a>
|
||||
<hr class="mt-0 mb-4"> {% endcomment %}
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-8">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
8
backend/serviceCRM/templates/list.html
Normal file
8
backend/serviceCRM/templates/list.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
|
||||
{% render_table object_list %}
|
||||
|
||||
{% endblock%}
|
||||
20
backend/serviceCRM/templates/serviceCRM/Insert_list.html
Normal file
20
backend/serviceCRM/templates/serviceCRM/Insert_list.html
Normal file
@@ -0,0 +1,20 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
<!-- Load dependencies -->
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
|
||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||
crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
|
||||
<script type="text/javascript" charset="utf8" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
|
||||
|
||||
<!-- Load js for initializing tables via their server-side options -->
|
||||
<script type="text/javascript" charset="utf8" src="{% static 'js/datatableview.js' %}"></script>
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
datatableview.initialize($('.datatable'));
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Render the table skeleton, includes the .datatable class for the on-ready initializer. -->
|
||||
{{ datatable }}
|
||||
0
backend/serviceCRM/templates/serviceCRM/delete.html
Normal file
0
backend/serviceCRM/templates/serviceCRM/delete.html
Normal file
6
backend/serviceCRM/templates/serviceCRM/done.html
Normal file
6
backend/serviceCRM/templates/serviceCRM/done.html
Normal file
@@ -0,0 +1,6 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
|
||||
{% block content %}
|
||||
{% render_table table %}
|
||||
{%endblock%}
|
||||
13
backend/serviceCRM/templates/serviceCRM/edit.html
Normal file
13
backend/serviceCRM/templates/serviceCRM/edit.html
Normal file
@@ -0,0 +1,13 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block title %}Edit{% endblock %}
|
||||
{% block content %}
|
||||
{% csrf_token %}
|
||||
<form method="post">
|
||||
<div class="form-group">
|
||||
{% csrf_token %}
|
||||
{{form.as_p}}
|
||||
<input type="submit" class="btn btn-success" value="Update">
|
||||
<input type="submit" class="btn btn-danger" value="Delete" formaction="{% url 'delete' id=object.id %}">
|
||||
</div>
|
||||
</form>
|
||||
{% endblock%}
|
||||
11
backend/serviceCRM/templates/serviceCRM/form.html
Normal file
11
backend/serviceCRM/templates/serviceCRM/form.html
Normal file
@@ -0,0 +1,11 @@
|
||||
{% extends 'base.html' %}
|
||||
{% block content %}
|
||||
{% csrf_token %}
|
||||
<form action="/insert/" method="post">
|
||||
<div class="form-group">
|
||||
{% csrf_token %}
|
||||
{{form.as_p}}
|
||||
<input type="submit" class="btn btn-success" value="Submit">
|
||||
</div>
|
||||
</form>
|
||||
{% endblock%}
|
||||
65
backend/serviceCRM/templates/serviceCRM/id.html
Normal file
65
backend/serviceCRM/templates/serviceCRM/id.html
Normal file
@@ -0,0 +1,65 @@
|
||||
<index>
|
||||
<title>
|
||||
Nalog
|
||||
</title>
|
||||
<body>
|
||||
{# <h1>Name:{{ name}}</h1>#}
|
||||
{# <h1>Phone:{{ phone }}</h1>#}
|
||||
{# <h1>Description:{{ desc }}</h1>#}
|
||||
{# <h1>Date:{{ date }}</h1>#}
|
||||
<!-- CSS Code: Place this code in the document's head (between the 'head' tags) -->
|
||||
<style>
|
||||
table.GeneratedTable {
|
||||
width: 100%;
|
||||
background-color: #ffffff;
|
||||
border-collapse: collapse;
|
||||
border-width: 2px;
|
||||
border-color: #ffcc00;
|
||||
border-style: solid;
|
||||
color: #000000;
|
||||
}
|
||||
thead{
|
||||
color:#f3f2f5
|
||||
}
|
||||
|
||||
table.GeneratedTable td, table.GeneratedTable th {
|
||||
border-width: 2px;
|
||||
border-color: #ffcc00;
|
||||
border-style: solid;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
table.GeneratedTable thead {
|
||||
background-color: #ffcc00;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- HTML Code: Place this code in the document's body (between the 'body' tags) where the table should appear -->
|
||||
<table class="GeneratedTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Phone</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{{ name}} </td>
|
||||
<td>{{ phone }}</td>
|
||||
<td>{{ date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3" style="font-size: 20px;background-color:#ffcc00;color:#f3f2f5">Опис на проблем:</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">{{ desc }}</td>
|
||||
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- Codes by Quackit.com -->
|
||||
|
||||
|
||||
</body>
|
||||
</index>
|
||||
5
backend/serviceCRM/templates/serviceCRM/list.html
Normal file
5
backend/serviceCRM/templates/serviceCRM/list.html
Normal file
@@ -0,0 +1,5 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load render_table from django_tables2 %}
|
||||
{% block content %}
|
||||
{% render_table table %}
|
||||
{% endblock%}
|
||||
83
backend/serviceCRM/templates/serviceCRM/nalog.html
Normal file
83
backend/serviceCRM/templates/serviceCRM/nalog.html
Normal file
@@ -0,0 +1,83 @@
|
||||
{% block content %}
|
||||
{% load static %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Servicing Ticket</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.header img {
|
||||
max-width: 150px;
|
||||
}
|
||||
.ticket {
|
||||
border: 2px solid #000;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ticket-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.ticket-info label {
|
||||
font-weight: bold;
|
||||
}
|
||||
.ticket-description {
|
||||
border-top: 2px solid #000;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin-bottom: 5 0px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="{% static 'fer-logo.png' %}" class="center" alt="Company Logo">
|
||||
</div>
|
||||
<div class="ticket">
|
||||
<div class="ticket-info">
|
||||
<label>Име и презиме:</label> {{ name }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Телефонски број:</label> {{phone}}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Датум:</label> {{date}}
|
||||
</div>
|
||||
<div class="ticket-description">
|
||||
<label><b>Опис на дефект:</b></label> {{ desc }}
|
||||
</div>
|
||||
</div>
|
||||
<div style="height:150px;"></div>
|
||||
<div class="ticket">
|
||||
<div class="ticket-info">
|
||||
<label>Име и презиме:</label> {{ name }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Телефонски број:</label> {{ phone }}
|
||||
</div>
|
||||
<div class="ticket-info">
|
||||
<label>Датум:</label> {{ date }}
|
||||
</div>
|
||||
<div class="ticket-description">
|
||||
<label><b>Опис на дефект:</b></label> {{ desc }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% endblock %}
|
||||
35
backend/serviceCRM/tests.py
Normal file
35
backend/serviceCRM/tests.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from django.test import TestCase, RequestFactory
|
||||
from django.urls import reverse
|
||||
from .models import Insert
|
||||
from .views import InsertListView, InsertNew, Update, Nalog, Done
|
||||
|
||||
class InsertListViewTest(TestCase):
|
||||
def test_view_url_exists_at_desired_location(self):
|
||||
response = self.client.get('/list/') # replace with your actual url
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
class InsertNewTest(TestCase):
|
||||
def test_view_url_exists_at_desired_location(self):
|
||||
response = self.client.get('/insert/') # replace with your actual url
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
class UpdateTest(TestCase):
|
||||
def setUp(self):
|
||||
self.insert = Insert.objects.create(name="Test", phone="1234567890", description="Test description", done=False, repair="Test repair")
|
||||
|
||||
def test_view_url_exists_at_desired_location(self):
|
||||
response = self.client.get(reverse('update', args=(self.insert.id,))) # replace 'update' with your actual url name
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
class NalogTest(TestCase):
|
||||
def setUp(self):
|
||||
self.insert = Insert.objects.create(name="Test", phone="1234567890", description="Test description", done=False, repair="Test repair")
|
||||
|
||||
def test_view_url_exists_at_desired_location(self):
|
||||
response = self.client.get(reverse('/nalog/', args=(self.insert.id,))) # replace 'nalog' with your actual url name
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
class DoneTest(TestCase):
|
||||
def test_view_url_exists_at_desired_location(self):
|
||||
response = self.client.get('/done/') # replace with your actual url
|
||||
self.assertEqual(response.status_code, 200)
|
||||
31
backend/serviceCRM/urls.py
Normal file
31
backend/serviceCRM/urls.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
URL configuration for serviceCRM project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views.py. For more information please see:
|
||||
https://docs.djangoproject.com/en/4.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views.py
|
||||
1. Add an import: from my_app import views.py
|
||||
2. Add a URL to urlpatterns: path('', views.py.home, name='home')
|
||||
Class-based views.py
|
||||
1. Add an import: from other_app.views.py import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
import serviceCRM.views as view
|
||||
|
||||
urlpatterns = [
|
||||
path("", view.InsertListView.as_view(), name="index"),
|
||||
path('admin/', admin.site.urls),
|
||||
path("insert/", view.InsertNew.insert, name="insert"),
|
||||
path("edit/<int:pk>/", view.Update.as_view(), name="update"),
|
||||
path("nalog/<int:id>/", view.Nalog, name="nalog"),
|
||||
path("delete/<int:id>/", view.Delete.delete, name="delete"),
|
||||
path("done/", view.Done.as_view(), name="done"),
|
||||
path("done/<int:id>/", view.Done.done_by_id, name="done"),
|
||||
path("datatable/", view.DatatableView.as_view(), name="datatable"),
|
||||
]
|
||||
74
backend/serviceCRM/views.py
Normal file
74
backend/serviceCRM/views.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from django.views import generic
|
||||
|
||||
from .forms import InputForm
|
||||
from .models import Insert
|
||||
from .tables import DoneInsertTable, InsertTable
|
||||
|
||||
from django_tables2 import SingleTableView
|
||||
from datatableview.views import DatatableView
|
||||
|
||||
class InsertListView(SingleTableView):
|
||||
model = Insert
|
||||
table_class = InsertTable
|
||||
template_name = 'serviceCRM/list.html'
|
||||
|
||||
class InsertNew(generic.View):
|
||||
model = Insert
|
||||
template_name = "serviceCRM/form.html"
|
||||
|
||||
def insert(request):
|
||||
if request.method == 'POST':
|
||||
form = InputForm(request.POST)
|
||||
if form.is_valid():
|
||||
ticket = form.save()
|
||||
print("Raboti")
|
||||
return HttpResponseRedirect(f"/nalog/{ticket.id}/")
|
||||
else:
|
||||
form = InputForm()
|
||||
ch
|
||||
return render(request, InsertNew.template_name, {'form': form})
|
||||
|
||||
class Update(generic.UpdateView):
|
||||
model = Insert
|
||||
template_name = "serviceCRM/edit.html"
|
||||
fields = ["name", "phone", "description","note", "done", "repair", "plateno"]
|
||||
success_url = '/'
|
||||
|
||||
|
||||
def Nalog(request, id):
|
||||
try:
|
||||
data = Insert.objects.get(id=id)
|
||||
except:
|
||||
return HttpResponseRedirect("/")
|
||||
template = "serviceCRM/nalog.html"
|
||||
context = {"name": data.name, "phone": data.phone, "desc": data.description, "date": data.date}
|
||||
return render(request, template, context)
|
||||
|
||||
class Done(SingleTableView):
|
||||
model = Insert
|
||||
table_data = Insert.objects.filter(done=True)
|
||||
table_class = DoneInsertTable
|
||||
template_name = 'serviceCRM/done.html'
|
||||
|
||||
def done_by_id(request, id):
|
||||
try:
|
||||
req = get_object_or_404(Insert, id=id)
|
||||
except:
|
||||
return HttpResponseRedirect("/done/")
|
||||
context = {"name": req.name, "phone": req.phone, "desc": req.description, "date": req.date}
|
||||
return HttpResponse(f"Report ID: {id} \nName: {req.name} \nPhone: {req.phone} \nDescription: {req.description} \n Note:{req.note} \nDate: {req.date} \nDone: {req.done} \nRepair: {req.repair} \n Plateno: {req.plateno} \n")
|
||||
|
||||
class Delete(generic.View):
|
||||
model = Insert
|
||||
|
||||
def delete(request, id):
|
||||
req = get_object_or_404(Insert, id=id)
|
||||
req.delete()
|
||||
return HttpResponseRedirect("/")
|
||||
|
||||
class DatatableView(DatatableView):
|
||||
model = Insert
|
||||
template_name = 'serviceCRM/Insert_list.html'
|
||||
|
||||
16
backend/serviceCRM/wsgi.py
Normal file
16
backend/serviceCRM/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for serviceCRM project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'serviceCRM.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
Reference in New Issue
Block a user