Ultimo Commit antes del apagon (Respaldo)

This commit is contained in:
fjrodriguez
2023-05-03 11:06:27 -06:00
parent 3b70ad09ca
commit 8b9b17a79d
21 changed files with 515 additions and 17 deletions

View File

@@ -15,7 +15,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
SECRET_KEY = os.getenv("adminAS_KEY") SECRET_KEY = os.getenv("adminAS_KEY")
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False DEBUG = True
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = ['*']
# Application definition # Application definition
@@ -34,6 +34,7 @@ INSTALLED_APPS = [
'widget_tweaks', 'widget_tweaks',
'Clientes', 'Clientes',
'IMMEX',
'Sistemas', 'Sistemas',
] ]
REST_FRAMEWORK = { REST_FRAMEWORK = {

View File

@@ -31,6 +31,7 @@ urlpatterns = [
path('accounts/', include('allauth.urls')), path('accounts/', include('allauth.urls')),
path('DRF_Token/', obtain_auth_token, name='DRF_Token'), path('DRF_Token/', obtain_auth_token, name='DRF_Token'),
path('', include('Clientes.urls')), path('', include('Clientes.urls')),
path('IMMEX/', include('IMMEX.urls')),
path('sistemas/',include('Sistemas.urls')), path('sistemas/',include('Sistemas.urls')),
path('403/', permission_denied_view), path('403/', permission_denied_view),

View File

@@ -419,11 +419,9 @@ class CancelaTimbre(APIView):
obj={'uuid':f'{timbre.uuid}_','rfcc':timbre.rfcc,'fecha':timbre.fecha,'folio':timbre.folio, obj={'uuid':f'{timbre.uuid}_','rfcc':timbre.rfcc,'fecha':timbre.fecha,'folio':timbre.folio,
'serie':timbre.serie,'tipo':'Cancela','rfcp':timbre.rfcp,'modo':'Normal'} 'serie':timbre.serie,'tipo':'Cancela','rfcp':timbre.rfcp,'modo':'Normal'}
else: else:
fecha=request.data.get('fecha', None) fecha=request.data.get('fecha', None)
folio=request.data.get('folio', None) folio=request.data.get('folio', None)
serie=request.data.get('serie', None) serie=request.data.get('serie', '')
rfcp_encoded=request.data.get('rfcp', None) rfcp_encoded=request.data.get('rfcp', None)
rfcp = urllib.parse.unquote(rfcp_encoded) rfcp = urllib.parse.unquote(rfcp_encoded)
@@ -526,8 +524,8 @@ class ClientesCreateView(UserPassesTestMixin,LoginRequiredMixin,CreateView):
form_class = ClienteForm form_class = ClienteForm
success_url='/' success_url='/'
template_name='Clientes/edit_cliente.html' template_name='Clientes/edit_cliente.html'
def test_func(self): def test_func(self):
#self.request.user.groups.all()
return self.request.user.groups.filter(name= 'admin_soft') return self.request.user.groups.filter(name= 'admin_soft')
def form_valid(self, form): def form_valid(self, form):

0
IMMEX/__init__.py Normal file
View File

5
IMMEX/admin.py Normal file
View File

@@ -0,0 +1,5 @@
from django.contrib import admin
from . models import Sistemas_por_cliente_A24, ClientesA24
admin.site.register(Sistemas_por_cliente_A24)
admin.site.register(ClientesA24)

6
IMMEX/apps.py Normal file
View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class ImmexConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'IMMEX'

24
IMMEX/forms.py Normal file
View File

@@ -0,0 +1,24 @@
from django import forms
from .models import ClientesA24
from datetime import datetime
class ClienteForm_IMMEX(forms.ModelForm):
fecha_baja = forms.DateField(
required=False,
initial=datetime.now(),
input_formats=["%Y-%m-%d"],
widget=forms.DateInput(attrs={'type':'date'},format="%Y-%m-%d")
)
class Meta:
model = ClientesA24
fields = ('RFC','Nombre','Activo','fecha_baja', )
def clean(self):
super(ClienteForm_IMMEX,self).clean()
Activo = self.cleaned_data.get("Activo")
fecha_baja = self.cleaned_data.get("fecha_baja")
if Activo and fecha_baja:
self._errors['fecha_baja'] = self.error_class(["El parametro activo no puede estar seleccionado si hay fecha de baja"])
return self.cleaned_data

View File

@@ -0,0 +1,42 @@
# Generated by Django 4.1.3 on 2023-04-26 16:55
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('Sistemas', '0019_alter_device_options'),
]
operations = [
migrations.CreateModel(
name='ClientesA24',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('RFC', models.CharField(max_length=13, unique=True)),
('Nombre', models.CharField(max_length=100)),
('Activo', models.BooleanField(default=False)),
('fecha_baja', models.DateField(blank=True, null=True)),
],
options={
'ordering': ('-Activo', 'RFC'),
},
),
migrations.CreateModel(
name='Sistemas_por_cliente_A24',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('num_licencias', models.IntegerField(default=1)),
('cliente', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cliente_spc_IMMEX', to='IMMEX.clientesa24')),
('id_sistema', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sistema_spc_IMMEX', to='Sistemas.sistema')),
],
options={
'ordering': ('-cliente', 'id_sistema'),
'unique_together': {('id_sistema', 'cliente')},
},
),
]

View File

25
IMMEX/models.py Normal file
View File

@@ -0,0 +1,25 @@
from django.db import models
from Sistemas.models import Sistema
class ClientesA24(models.Model):
RFC = models.CharField(max_length=13, unique=True)
Nombre = models.CharField(max_length=100)
Activo = models.BooleanField(default=False)
fecha_baja = models.DateField(blank=True,null=True)
class Meta:
ordering = ('-Activo','RFC',)
def __str__(self):
return self.Nombre
class Sistemas_por_cliente_A24(models.Model):
id_sistema= models.ForeignKey(Sistema, related_name='sistema_spc_IMMEX', on_delete=models.CASCADE)
cliente = models.ForeignKey(ClientesA24, related_name='cliente_spc_IMMEX', on_delete=models.CASCADE)
num_licencias= models.IntegerField(default=1)
def __str__(self):
return f'{self.cliente.Nombre}'
class Meta:
ordering= ('-cliente','id_sistema')
unique_together = ('id_sistema', 'cliente')

7
IMMEX/serializers.py Normal file
View File

@@ -0,0 +1,7 @@
from rest_framework import serializers
from .models import ClientesA24
class ClientesA24Serailizer(serializers.ModelSerializer):
class Meta:
model =ClientesA24
fields = ('RFC', 'Nombre','Activo','fecha_baja',)

3
IMMEX/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

10
IMMEX/urls.py Normal file
View File

@@ -0,0 +1,10 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.Sistemas_xCliente_IMMEX_ListView.as_view(), name='sistemasXcli_IMMEX'),
path('create_sistema/',views.Sistemas_xCliente_IMMEX_CreateView.as_view(), name='create_sistemaIMMEX'),
path('create_Cliente/', views.ClientesIMMEX_CreateView.as_view(), name='ClientesIMMEX_Create'),
path('checkRfcA24/', views.Check_IMMEX_RFC.as_view(), name='checkRfcA24' ),
]

91
IMMEX/views.py Normal file
View File

@@ -0,0 +1,91 @@
from django.shortcuts import render
from django.http import JsonResponse
from django.urls import reverse_lazy
from Sistemas.models import Sistema
from .models import Sistemas_por_cliente_A24, ClientesA24
from django.views.generic.edit import CreateView
from django.views.generic.list import ListView
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .forms import ClienteForm_IMMEX
from .serializers import ClientesA24Serailizer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from Sistemas.permissions import ItsAdminToken
import urllib.parse
import traceback
class Sistemas_xCliente_IMMEX_ListView(UserPassesTestMixin,LoginRequiredMixin, ListView):
model = Sistemas_por_cliente_A24
paginate_by = 100
template_name = 'IMMEX/xclientes/lista.html'
def test_func(self):
res = self.request.user.groups.filter(name= 'admin_soft')
if not res:
messages.error(self.request, 'Lo sentimos. La página que buscas no está disponible o no cuentas con los permisos.')
return res
class Sistemas_xCliente_IMMEX_CreateView(UserPassesTestMixin,LoginRequiredMixin,CreateView):
model = Sistemas_por_cliente_A24
fields = ['id_sistema', 'cliente', 'num_licencias']
template_name = 'IMMEX/xclientes/sistema_create_IMMEX.html'
success_url = reverse_lazy('sistemasXcli_IMMEX')
def test_func(self):
res = self.request.user.groups.filter(name= 'admin_soft')
if not res:
messages.error(self.request, 'Lo sentimos. La página que buscas no está disponible o no cuentas con los permisos.')
return res
class ClientesIMMEX_CreateView(CreateView):
model = ClientesA24
form_class = ClienteForm_IMMEX
success_url = '/IMMEX/'
template_name = 'IMMEX/xclientes/edit_cliente.html'
def form_valid(self, form):
response = super().form_valid(form)
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
data={
'id':self.object.id,
'RFC':self.object.RFC,
'Nombre':self.object.Nombre,
'Activo':self.object.Activo,
}
return JsonResponse(data)
else:
return response
def form_invalid(self,form):
response = super().form_invalid(form)
if self.request.headers.get('X-Requested-With') == 'XMLHttpRequest':
errors = form.errors.as_text()
return JsonResponse({'errors':f'{errors}'},status=200,content_type='application/json')
else:
return response
"""---------API VIEWS---------"""
class Check_IMMEX_RFC(APIView):
"""Verifica que el cliente pueda Timbrar"""
permission_classes = (IsAuthenticated,ItsAdminToken,)
def post(self,request,*args, **kwargs):
rfc= request.data.get('RFC')
try:
clienteA24 , created = ClientesA24.objects.get_or_create(RFC=rfc)
serializer = ClientesA24Serailizer(clienteA24)
if created:
clienteA24.Activo =True
clienteA24.Nombre = rfc
clienteA24.save()
if not serializer.is_valid:
return Response({'Error':f'{serializer.errors}','isError':True},status=200)
return Response(serializer.data)
except Exception as E:
return Response({'Error':f'check_RFC:{E} RFC:{rfc}','isError':True})

View File

@@ -17,12 +17,12 @@ from .views import (
CheckVersionView, CheckVersionView,
UploadZipVersionView, UploadZipVersionView,
Sistema_CreateView, Sistema_CreateView,
Custom_Login,
#function #function
download_version_FromServer, download_version_FromServer,
uploadZipViewHTML, uploadZipViewHTML,
) )
urlpatterns = [ urlpatterns = [
path('',SistemasXCliente_ListView.as_view(),name='lista_sistmas'), path('',SistemasXCliente_ListView.as_view(),name='lista_sistmas'),
@@ -39,4 +39,5 @@ urlpatterns = [
path('download_version_FromServer/',download_version_FromServer, name='downloadVersionFromServer'), path('download_version_FromServer/',download_version_FromServer, name='downloadVersionFromServer'),
path('uploadZip/', UploadZipVersionView.as_view(), name='uploadZip'), path('uploadZip/', UploadZipVersionView.as_view(), name='uploadZip'),
path('uploadZip2/', uploadZipViewHTML, name="uploadZipViewHTML"), path('uploadZip2/', uploadZipViewHTML, name="uploadZipViewHTML"),
path('login/', Custom_Login.as_view(), name="Customlogin"),
] ]

View File

@@ -15,6 +15,8 @@ from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated from rest_framework.permissions import IsAuthenticated
from rest_framework import status, permissions from rest_framework import status, permissions
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth import authenticate, login
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
@@ -221,6 +223,7 @@ class Sistema_CreateView(CreateView):
========================= API Views ========================= API Views
''' '''
class GetDeviceToken(APIView): class GetDeviceToken(APIView):
"""Recobra el Token DRF del Device""" """Recobra el Token DRF del Device"""
authentication_classes= [TokenAuthentication] authentication_classes= [TokenAuthentication]
@@ -344,3 +347,23 @@ class CheckVersionView(APIView):
except Exception as ex: except Exception as ex:
BitacoraErrores.objects.create(level=2, message=str(ex), traceback=traceback.format_exc(), view='Sistemas.CheckVersionView') BitacoraErrores.objects.create(level=2, message=str(ex), traceback=traceback.format_exc(), view='Sistemas.CheckVersionView')
return Response({'Error':f'{ex}','isError':True}) return Response({'Error':f'{ex}','isError':True})
class Custom_Login(APIView):
"""Autentica al device"""
authentication_classes= [TokenAuthentication]
permissions_classes=[IsAuthenticated, HasAuthorizationHeader]
def post(self, request):
username = request.data.get('username')
password = request.data.get('password')
try:
user = authenticate(request, username=username,password=password)
if user is not None:
login(request,user)
return Response({'access':True})
else:
return Response({'access':False})
except Exception as ex:
BitacoraErrores.objects.create(level=2, message=str(ex), traceback=traceback.format_exc(), view='Sistemas.Custom_Login')
return Response({'access':False})

View File

@@ -0,0 +1,97 @@
{% extends 'base.html' %}
{% load widget_tweaks %}
{% block title %}Add Cliente IMMEX {% endblock title %}
{% block content %}
<form method="POST" action="." id="cliente-form">
{% csrf_token %}
<div class="form-group">
<label for="{{form.RFC.name}}"><strong> {{form.RFC.label|capfirst}} </strong></label>
{% render_field form.RFC id+="add" id+=form.RFC.name placeholder=form.RFC.label class="form-control" type="text" autocomplete="off" %}
</div>
<div class="form-group">
<label for="{{form.Nombre.name}}"><strong> {{form.Nombre.label|capfirst}} </strong></label>
{% render_field form.Nombre id+="add" id+=form.Nombre.name placeholder=form.Nombre.label class="form-control" type="text" autocomplete="off" %}
</div>
<div class="form-group form-check">
{% render_field form.Activo class+="form-checkbox" type="checkbox" %}
<label class="form-check-label" for="{{form.Activo.label}}">Activo</label>
</div>
<div class="form-group">
{% render_field form.fecha_baja.label %}
{% render_field form.fecha_baja placeholder=form.fecha_baja.label class+="form-control" type="date" %}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
{% endblock content %}
{% block scripts %}
<script>
document.addEventListener("DOMContentLoaded", ()=>{
if(window.name ==='popupWin')
{
document.querySelector("#cliente-form").addEventListener('submit',(event)=>{
event.preventDefault();
let form= event.target;
let url = `{% url 'ClientesIMMEX_Create' %}`;
let data = new FormData(form);
let xhr = new XMLHttpRequest();
xhr.open('POST',url);
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.onreadystatechange = ()=>{
if(xhr.readyState===XMLHttpRequest.DONE){
if(xhr.status===200){
let response = JSON.parse(xhr.responseText);
if(response.errors){
alert(response.errors)
}else{
window.opener.postMessage({data:response, windowName:'clientWindow'},window.location.origin);
window.close();
}
}else{
console.error('Request error ',xhr.statusText);
}
}
};
xhr.send(data);
});
}else{
console.log('not popupWin')
}
})
window.addEventListener("load", (event)=>{
if(!id_Activo.checked){
id_fecha_baja.setAttribute('required','')
}else{
id_fecha_baja.removeAttribute('requied')
}
})
id_fecha_baja.addEventListener('click',(event)=>{
if(id_Activo.checked){
event.preventDefault()
alert('El cliente esta activo necesita deseleccionar "Activo" y colocar fecha baja.')
return
}
})
id_Activo.addEventListener('click', (event)=>{
if(id_Activo.checked){
id_fecha_baja.value=''
id_fecha_baja.removeAttribute('required')
}else{
id_fecha_baja.setAttribute('required','')
}
})
</script>
{% endblock scripts %}

View File

@@ -0,0 +1,35 @@
{% extends "base.html" %}
{% block title %}
Sistemas Clientes IMMEX
{% endblock title %}
{% block content %}
<table class="table">
<thead class="thead-dark">
<tr>
<th scope="col">#</th>
<th scope="col">Sistema</th>
<th scope="col">Cliente</th>
<th scope="col">No. Licencias</th>
<th><a class="btn btn-outline-info" href="{% url 'create_sistemaIMMEX' %}">Agregar Sistema por cliente</a></th>
</tr>
</thead>
<tbody>
{% for row in object_list %}
<tr>
<th scope="row">{{row.id}}</th>
<td>{{row.id_sistema}}</td>
<td>{{row.cliente}}</td>
<td>{{row.num_licencias}}</td>
<td><a href="#" class="btn btn-info">Detalles</a></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock content %}

View File

@@ -0,0 +1,121 @@
{% extends 'base.html' %}
{% block content %}
<h1>Create a new Sistema IMMEX por cliente</h1>
<form method="post">
{% csrf_token %}
{% if form.non_field_errors %}
<div class="alert alert-danger" role="alert">
{% for error in form.non_field_errors %}
<p>{{ error }}</p>
{% endfor %}
</div>
{% endif %}
<div class="">
<div class="form-group">
<div class="form">
{{ form.id_sistema.label }}
{{ form.id_sistema }}
<button id="add-sistema-btn" type="button" class="btn btn-info">Add Sistema</button>
{% if form.id_sistema.errors %}
<ul class="errorlist">
{% for error in form.id_sistema.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
</div>
<div class="form-group">
{{ form.cliente.label}}
{{ form.cliente }}
<button id="add-cliente-btn" type="button" class="btn btn-info">Add Cliente</button>
{% if form.cliente.errors %}
<ul class="errorlist">
{% for error in form.cliente.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<div class="form-group">
{{ form.num_licencias.label }}
{{ form.num_licencias }}
{% if form.num_licencias.errors %}
<ul class="errorlist">
{% for error in form.num_licencias.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
</div>
<button class="btn btn-success" type="submit">Create</button>
</div>
</form>
{% endblock content %}
{% block scripts %}
<script>
document.addEventListener('DOMContentLoaded', function() {
/*add Sistema*/
document.querySelector('#add-sistema-btn').addEventListener('click', function() {
let parentWidth = window.innerWidth;
let parentHeight = window.innerHeight;
let childWidth = 800;
let childHeight = 600;
let left =(parentWidth - childWidth);
let top = (parentHeight - childHeight);
let popupWin = window.open("{% url 'create_sistemas_form' %}", "popupWin", "width=" + childWidth + ",height=" + childHeight + ",left=" + left + ",top=" + top);
popupWin.focus();
});
/*Add cliente*/
document.querySelector("#add-cliente-btn").addEventListener('click',()=>{
let parentWidth = window.innerWidth;
let parentHeight = window.innerHeight;
let childWidth = 800;
let childHeight = 600;
let left =(parentWidth - childWidth);
let top = (parentHeight - childHeight);
let popupWin = window.open("{% url 'ClientesIMMEX_Create' %}", "popupWin", "width=" + childWidth + ",height=" + childHeight + ",left=" + left + ",top=" + top);
popupWin.focus();
});
window.addEventListener('message', function(event) {
let response = event.data.data;
let windowName = event.data.windowName;
if(windowName==='clientWindow'){
let id_cliente = response.id;
let Nombre = response.Nombre;
let option= `<option value="${id_cliente}" selected> ${Nombre}</option>`;
document.querySelector("#id_cliente").insertAdjacentHTML('beforeend',option);
}
else if (windowName==='sistemaWindow'){
let id_sistema = response.id;
let nombre_sistema = response.nombre_sistema;
let version = response.version;
let option = '<option value="' + id_sistema + '" selected>' + nombre_sistema + ', version ' + version + '</option>';
document.querySelector('#id_id_sistema').insertAdjacentHTML('beforeend', option);
}
});
});
</script>
{% endblock scripts %}

View File

@@ -1,3 +1,6 @@
{% with request_path=request.path|slice:'/' %}
<nav class="navbar navbar-expand-lg navbar-light bg-light"> <nav class="navbar navbar-expand-lg navbar-light bg-light">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
@@ -7,8 +10,7 @@
<div class="collapse navbar-collapse" id="navbarTogglerDemo03"> <div class="collapse navbar-collapse" id="navbarTogglerDemo03">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0"> <ul class="navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item dropdown {% if request_path == '/' %}active{% endif %}">
<li class="nav-item dropdown active">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Timbres/Clientes Timbres/Clientes
</a> </a>
@@ -41,9 +43,14 @@
</li> </li>
{% endcomment %} {% endcomment %}
<li class="nav-item">
<a class="nav-link" href="/sistemas" target="_blank">Sistemas</a> <li class="nav-item {% if 'sistemas' in request_path %}active border{% endif %}">
<a class="nav-link" href="/sistemas" >Sistemas CFDI</a>
</li> </li>
<li class="nav-item {% if 'IMMEX' in request_path %}active border{% endif %}">
<a class="nav-link" href="{% url 'sistemasXcli_IMMEX' %}" >Sistemas IMMEX</a>
</li>
{% if request.user.is_superuser %} {% if request.user.is_superuser %}
<li class="nav-item"> <li class="nav-item">
<a class="nav-link" href="/admin" target="_blank">Admin site</a> <a class="nav-link" href="/admin" target="_blank">Admin site</a>
@@ -76,3 +83,4 @@
</li> </li>
</div> </div>
</nav> </nav>
{% endwith%}