first commit
This commit is contained in:
42
Client/FormsClient.py
Normal file
42
Client/FormsClient.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from django import forms
|
||||
from Client import models
|
||||
|
||||
class FormsClient(forms.ModelForm):
|
||||
class Meta:
|
||||
model = models.Client
|
||||
fields = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'phone',
|
||||
'professional',
|
||||
'double_workload',
|
||||
# 'feed_back',
|
||||
# 'msg_3_months',
|
||||
# 'msg_6_months',
|
||||
# 'msg_12_months',
|
||||
'notes',
|
||||
]
|
||||
widgets = {
|
||||
'first_name': forms.TextInput({'class':'form-control'}),
|
||||
'last_name': forms.TextInput({'class':'form-control'}),
|
||||
'notes': forms.Textarea({'class':'form-control','rows':3 , }),
|
||||
'phone': forms.NumberInput(attrs={'step': 1, }),
|
||||
'professional': forms.Select({'class':'form-control'}),
|
||||
'double_workload': forms.CheckboxInput({'class':''}),
|
||||
# 'msg_3_months': forms.CheckboxInput({'class':''}),
|
||||
# 'msg_6_months': forms.CheckboxInput({'class':''}),
|
||||
# 'msg_12_months': forms.CheckboxInput({'class':''}),
|
||||
# 'feed_back': forms.CheckboxInput({'class':''}),
|
||||
}
|
||||
labels={
|
||||
'first_name':'Nome',
|
||||
'last_name':'Sobrenome',
|
||||
'phone':'Telefone',
|
||||
'professional':'Profissinal',
|
||||
'double_workload':'Tempo Duplo',
|
||||
'notes':'Notas',
|
||||
# 'feed_back':'FeedBack',
|
||||
# 'msg_3_months':'FeedBack',
|
||||
# 'msg_6_months':'FeedBack',
|
||||
# 'msg_12_months':'FeedBack',
|
||||
}
|
||||
0
Client/__init__.py
Normal file
0
Client/__init__.py
Normal file
3
Client/admin.py
Normal file
3
Client/admin.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
6
Client/apps.py
Normal file
6
Client/apps.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ClientConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'Client'
|
||||
42
Client/migrations/0001_initial.py
Normal file
42
Client/migrations/0001_initial.py
Normal file
@@ -0,0 +1,42 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-01 11:15
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('Base', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Client',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('active', models.BooleanField(default=False)),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
('first_name', models.CharField(max_length=100)),
|
||||
('last_name', models.CharField(max_length=500)),
|
||||
('phone', models.DecimalField(decimal_places=0, max_digits=20)),
|
||||
('double_workload', models.BooleanField(default=False)),
|
||||
('feed_back', models.BooleanField(default=False)),
|
||||
('msg_3_months', models.BooleanField(default=False)),
|
||||
('msg_6_months', models.BooleanField(default=False)),
|
||||
('msg_12_months', models.BooleanField(default=False)),
|
||||
('notes', models.TextField(blank=True, null=True)),
|
||||
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_created', to=settings.AUTH_USER_MODEL)),
|
||||
('professional', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='ClientProfessional', to='Base.professional')),
|
||||
('updated_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='%(class)s_updated', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'ordering': ['first_name', 'last_name'],
|
||||
},
|
||||
),
|
||||
]
|
||||
0
Client/migrations/__init__.py
Normal file
0
Client/migrations/__init__.py
Normal file
BIN
Client/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
BIN
Client/migrations/__pycache__/0001_initial.cpython-312.pyc
Normal file
Binary file not shown.
BIN
Client/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
BIN
Client/migrations/__pycache__/__init__.cpython-312.pyc
Normal file
Binary file not shown.
23
Client/models.py
Normal file
23
Client/models.py
Normal file
@@ -0,0 +1,23 @@
|
||||
from django.db import models
|
||||
from Base.models import Professional , Base
|
||||
|
||||
# Lista de clientes
|
||||
class Client(Base):
|
||||
first_name = models.CharField(max_length=100)
|
||||
last_name = models.CharField(max_length=500)
|
||||
phone = models.DecimalField(max_digits=20,decimal_places=0)
|
||||
professional = models.ForeignKey(
|
||||
Professional,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='ClientProfessional'
|
||||
)
|
||||
double_workload = models.BooleanField(default=False)
|
||||
feed_back = models.BooleanField(default=False)
|
||||
msg_3_months = models.BooleanField(default=False)
|
||||
msg_6_months = models.BooleanField(default=False)
|
||||
msg_12_months = models.BooleanField(default=False)
|
||||
notes = models.TextField(null=True, blank=True)
|
||||
class Meta:
|
||||
ordering = ['first_name','last_name']
|
||||
def __str__(self):
|
||||
return f'{self.first_name} {self.last_name} {self.professional.symbol}'
|
||||
24
Client/templates/Client/Create.html
Normal file
24
Client/templates/Client/Create.html
Normal file
@@ -0,0 +1,24 @@
|
||||
{% extends "BaseLogin.html" %}
|
||||
{% block title %} List {% endblock %}
|
||||
{% block content %}
|
||||
|
||||
<div class="conteiner mt-4">
|
||||
<h3 class="display-6"> Cadastrar </h3>
|
||||
<div class="card col-md-10">
|
||||
<div class="card-body">
|
||||
<form method="post" class="form">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn btn-primary"> Salvar </button>
|
||||
</form>
|
||||
<a href="{% url 'ClientListView' %}" class="btn btn-secondary mt-3 "> Cancelar e Voltar </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
18
Client/templates/Client/Delete.html
Normal file
18
Client/templates/Client/Delete.html
Normal file
@@ -0,0 +1,18 @@
|
||||
{% extends "BaseLogin.html" %}
|
||||
{% block title %} Bank Accounts List {% endblock %}
|
||||
{% block content %}
|
||||
<div class="conteiner mt-4">
|
||||
<h3 class="display-6"> Deletar da Marcar </h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">Tem certeza que quer deletar ? </h3>
|
||||
<h1><strong>{{ object.first_name }} {{ object.last_name }}</strong></h1>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<button type="submit" class="btn btn-danger mt-3"> Deletar </button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{% url 'ClientListView' %}" class="btn btn-secondary mt-3 "> Cancelar e Voltar </a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
45
Client/templates/Client/Detail.html
Normal file
45
Client/templates/Client/Detail.html
Normal file
@@ -0,0 +1,45 @@
|
||||
{% extends "BaseLogin.html" %}
|
||||
{% block title %} Bank Accounts List {% endblock %}
|
||||
{% block content %}
|
||||
<div class="conteiner mt-4">
|
||||
<h3 class="display-6"> Detalhes do Banco </h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title">{{ object.first_name }} {{ object.last_name }}</h3><br>
|
||||
<p class="card-text">Tel.: {{ object.phone }}</p>
|
||||
<p class="card-text">Prof. de Preferencia : {{ object.professional }}</p>
|
||||
<p class="card-text">Tempo Duplo : {{ object.double_workload }}</p>
|
||||
<p class="card-text">Nota: {{ object.notes }}</p>
|
||||
<br>
|
||||
|
||||
<h3> Ultimas visitas </h3>
|
||||
<div class="col-4">
|
||||
<table class="table table-striped table-sm table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Dia </th>
|
||||
<th>Horario</th>
|
||||
<th>Profissinal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="table table-bordered">
|
||||
{% for client in clients %}
|
||||
<tr>
|
||||
<td>{{ client.date|date:"d/m/Y" }}</td>
|
||||
<td>{{ client.time }} </td>
|
||||
<td>{{ client.professional }} </td>
|
||||
</tr>
|
||||
{% empty %}
|
||||
<tr>
|
||||
<td colspan="2"> Nada </td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<a href="{% url 'ClientUpdateView' object.id %}" class="btn btn-secondary mt-3 "> Editar </a>
|
||||
</div>
|
||||
</div>
|
||||
<a href="{% url 'ClientListView' %}" class="btn btn-secondary mt-3 "> Cancelar e Voltar </a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
115
Client/templates/Client/List.html
Normal file
115
Client/templates/Client/List.html
Normal file
@@ -0,0 +1,115 @@
|
||||
{% extends "BaseLogin.html" %}
|
||||
{% block title %} List {% endblock %}
|
||||
{% block content %}
|
||||
<h1> Clientes </h1><br>
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<form method="get" action="{% url 'ClientListView' %}" id="filterForm">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="name"
|
||||
placeholder="Nome ou Sobrenome" value="{{ request.GET.name }}"
|
||||
onchange="document.getElementById('filterForm').submit();"
|
||||
>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<form method="get" action="{% url 'ClientListView' %}" id="filterForm2">
|
||||
<div class="input-group">
|
||||
<input type="number" class="form-control" name="number"
|
||||
placeholder="Telefone" value="{{ request.GET.number }}"
|
||||
onchange="document.getElementById('filterForm2').submit();"
|
||||
>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-search"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{# <div class="col-md-3">#}
|
||||
{# <form method="get" action="{% url 'ClientListView' %}" id="filterForm3">#}
|
||||
{# <div class="input-group">#}
|
||||
{# <input type="hidden" class="form-control" name="all"#}
|
||||
{# placeholder="" value="all"#}
|
||||
{# onchange="document.getElementById('filterForm3').submit();"#}
|
||||
{# >#}
|
||||
{# <button type="submit" class="btn btn-primary"> Tudo#}
|
||||
{# <i class="bi bi-search"></i>#}
|
||||
{# </button>#}
|
||||
{# </div>#}
|
||||
{# </form>#}
|
||||
{# </div>#}
|
||||
{# {% if perms.brands.add_brands %}#}
|
||||
<div class="col-md-1">
|
||||
<a href="{% url 'ClientCreateView' %}" class="btn btn-success float-end">
|
||||
{# <i class="bi bi-plus"></i> #}
|
||||
Criar </a>
|
||||
</div>
|
||||
{# {% endif %}#}
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped table-bordered">
|
||||
<thead class="thead-dark">
|
||||
<tr class="text-center">
|
||||
<th width="5%"> Marcar </th>
|
||||
<th> Nome </th>
|
||||
<th> Sobrenome </th>
|
||||
<th width="10%"> Telefone </th>
|
||||
<th width="10%"> Profissinal </th>
|
||||
<th width="08%"> T. D. </th>
|
||||
<th width="05%"> FeedBack </th>
|
||||
<th width="15%"> Notas </th>
|
||||
<th width="5%"> Produto </th>
|
||||
<th width="15%"> Ações </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody align="center">
|
||||
{% for Client in Clients %}
|
||||
<tr align="center" vertical-align="center">
|
||||
<td>
|
||||
<form method="get" action="{% url 'MovCalendarCreateCustom' %}" >
|
||||
<input type="hidden" name="Client" value="{{ Client.id }}">
|
||||
<button type="submit" class="btn btn-primary"> Marcar </button>
|
||||
</form>
|
||||
</td>
|
||||
<td> {{ Client.first_name }} </td>
|
||||
<td> {{ Client.last_name }} </td>
|
||||
<td> {{ Client.phone }} </td>
|
||||
<td> {{ Client.professional.symbol }} {{ Client.professional }}</td>
|
||||
<td> {% if Client.double_workload %} <i class="bi bi-check-circle-fill text-success "></i>
|
||||
{% else %} <i class="bi bi-x-circle-fill text-danger "></i> {% endif %} </td>
|
||||
<td> {% if Client.feed_back %} <i class="bi bi-check-circle-fill text-success "></i>
|
||||
{% else %} <i class="bi bi-x-circle-fill text-danger "></i> {% endif %} </td>
|
||||
<td> {{ Client.notes }} </td>
|
||||
<td>
|
||||
<form method="get" action="{% url 'MovProductCreateCustom' %}" >
|
||||
<input type="hidden" name="Client" value="{{ Client.id }}">
|
||||
<button type="submit" class="btn btn-primary"> Produto </button>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% url 'ClientDetailView' Client.id %}" class="btn btn-info btn-sm">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
{# {% if perms.brands.change_brands %}#}
|
||||
<a href="{% url 'ClientUpdateView' Client.id %}" class="btn btn-warning btn-sm">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
{# {% endif %}#}
|
||||
{# {% if perms.brands.delete_brands %}#}
|
||||
<a href="{% url 'ClientDeleteView' Client.id %}" class="btn btn-danger btn-sm">
|
||||
<i class="bi bi-trash"></i>
|
||||
</a>
|
||||
{# {% endif %}#}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'components/_pagination.html' %}
|
||||
{% endblock %}
|
||||
17
Client/templates/Client/Update.html
Normal file
17
Client/templates/Client/Update.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{% extends "BaseLogin.html" %}
|
||||
{% block title %} Bank Accounts List {% endblock %}
|
||||
{% block content %}
|
||||
<div class="conteiner mt-4">
|
||||
<h3 class="display-6"> Editar Bancos </h3>
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form method="post" class="form">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit" class="btn btn-primary"> Salvar </button>
|
||||
</form>
|
||||
<a href="{% url 'ClientListView' %}" class="btn btn-secondary mt-3 "> Cancelar e Voltar </a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
3
Client/tests.py
Normal file
3
Client/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
12
Client/urlsClient.py
Normal file
12
Client/urlsClient.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from django.urls import path
|
||||
from Client import viewsClient
|
||||
|
||||
urlpatterns = [
|
||||
# URLs de Client
|
||||
path('/', viewsClient.ClientListView.as_view(), name='ClientListView'),
|
||||
path('/Create', viewsClient.ClientCreateView.as_view(), name='ClientCreateView'),
|
||||
path('/<int:pk>/Detail', viewsClient.ClientDetailView.as_view(), name='ClientDetailView'),
|
||||
path('/<int:pk>/Update', viewsClient.ClientUpdateView.as_view(), name='ClientUpdateView'),
|
||||
path('/<int:pk>/Delete', viewsClient.ClientDeleteView.as_view(), name='ClientDeleteView'),
|
||||
|
||||
]
|
||||
61
Client/viewsClient.py
Normal file
61
Client/viewsClient.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin , PermissionRequiredMixin
|
||||
from Client import models, FormsClient
|
||||
from Movement.models import Calendar
|
||||
from django.urls import reverse_lazy
|
||||
# from django.core import serializers
|
||||
|
||||
class ClientListView(LoginRequiredMixin, PermissionRequiredMixin, ListView):
|
||||
model = models.Client
|
||||
template_name = 'Client/List.html'
|
||||
context_object_name = 'Clients'
|
||||
# paginate_by = 5
|
||||
permission_required = 'Client.view_client'
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset()
|
||||
name = self.request.GET.get('name')
|
||||
number = self.request.GET.get('number')
|
||||
# all = self.request.GET.get('all')
|
||||
if name:
|
||||
queryset = queryset.filter(first_name__icontains=name) | queryset.filter(last_name__icontains=name)
|
||||
elif number:
|
||||
queryset = queryset.filter(phone__icontains=number)
|
||||
# elif all:
|
||||
# queryset = queryset.all()
|
||||
else:
|
||||
queryset = queryset.none()
|
||||
return queryset
|
||||
|
||||
|
||||
class ClientCreateView(LoginRequiredMixin, PermissionRequiredMixin, CreateView):
|
||||
model = models.Client
|
||||
template_name = 'Client/Create.html'
|
||||
form_class = FormsClient.FormsClient
|
||||
success_url = reverse_lazy('ClientListView')
|
||||
permission_required = 'Client.add_client'
|
||||
|
||||
|
||||
class ClientDetailView(LoginRequiredMixin, PermissionRequiredMixin, DetailView):
|
||||
model = models.Client
|
||||
template_name = 'Client/Detail.html'
|
||||
permission_required = 'Client.view_client'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['clients'] = Calendar.objects.filter(
|
||||
client__id=self.object.id
|
||||
).order_by('-id').distinct()[:3]
|
||||
return context
|
||||
|
||||
class ClientUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
|
||||
model = models.Client
|
||||
template_name = 'Client/Update.html'
|
||||
form_class = FormsClient.FormsClient
|
||||
success_url = reverse_lazy('ClientListView')
|
||||
permission_required = 'Client.change_client'
|
||||
|
||||
class ClientDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteView):
|
||||
model = models.Client
|
||||
template_name = 'Client/Delete.html'
|
||||
success_url = reverse_lazy('ClientListView')
|
||||
permission_required = 'Client.delete_client'
|
||||
Reference in New Issue
Block a user