@@ -9,21 +9,16 @@ import pytz
|
|||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = 'django-insecure-5*mm&uf5zq@t6nrs_5z8-_qtyapm^3&yz^wqqkc_a!v(!ulj-^'
|
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 = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['*']
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
@@ -39,8 +34,9 @@ INSTALLED_APPS = [
|
|||||||
'allauth.account',
|
'allauth.account',
|
||||||
'allauth.socialaccount',
|
'allauth.socialaccount',
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
'Admin',
|
|
||||||
'Clientes',
|
'Clientes',
|
||||||
|
'Sistemas',
|
||||||
]
|
]
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
'DEFAULT_AUTHENTICATION_CLASSES': [
|
'DEFAULT_AUTHENTICATION_CLASSES': [
|
||||||
@@ -57,9 +53,7 @@ MIDDLEWARE = [
|
|||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
]
|
]
|
||||||
|
|
||||||
ROOT_URLCONF = 'Admin.urls'
|
ROOT_URLCONF = 'Admin.urls'
|
||||||
|
|
||||||
TEMPLATES = [
|
TEMPLATES = [
|
||||||
{
|
{
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
@@ -68,11 +62,12 @@ TEMPLATES = [
|
|||||||
'OPTIONS': {
|
'OPTIONS': {
|
||||||
'context_processors': [
|
'context_processors': [
|
||||||
'django.template.context_processors.debug',
|
'django.template.context_processors.debug',
|
||||||
|
# `allauth` needs this from django
|
||||||
'django.template.context_processors.request',
|
'django.template.context_processors.request',
|
||||||
'django.contrib.auth.context_processors.auth',
|
'django.contrib.auth.context_processors.auth',
|
||||||
'django.contrib.messages.context_processors.messages',
|
'django.contrib.messages.context_processors.messages',
|
||||||
# `allauth` needs this from django
|
|
||||||
'django.template.context_processors.request',
|
#custom context processor
|
||||||
'Clientes.saldo_context_proc.get_saldo',
|
'Clientes.saldo_context_proc.get_saldo',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -104,14 +99,23 @@ ACCOUNT_LOGOUT_REDIRECT_URL = '/accounts/login/'
|
|||||||
ACCOUNT_SIGNUP_REDIRECT_URL =LOGIN_REDIRECT_URL
|
ACCOUNT_SIGNUP_REDIRECT_URL =LOGIN_REDIRECT_URL
|
||||||
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
ACCOUNT_LOGOUT_ON_PASSWORD_CHANGE = True
|
||||||
|
|
||||||
|
|
||||||
EMAIL_TIMEOUT = 10
|
EMAIL_TIMEOUT = 10
|
||||||
#EMAIL_USE_TLS = True
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_SUBJECT_PREFIX = 'AS Timbres'
|
||||||
|
if DEBUG :
|
||||||
|
EMAIL_USE_TLS = True
|
||||||
|
EMAIL_HOST = 'smtp.gmail.com'
|
||||||
|
EMAIL_PORT = 587
|
||||||
|
EMAIL_HOST_USER = 'aduanasoftpruebas@gmail.com'
|
||||||
|
EMAIL_HOST_PASSWORD = os.getenv("test_pwd_email")
|
||||||
|
#EMAIL_USE_SSL=False
|
||||||
|
else:
|
||||||
|
EMAIL_USE_TLS = False
|
||||||
EMAIL_HOST = 'secure.emailsrvr.com'
|
EMAIL_HOST = 'secure.emailsrvr.com'
|
||||||
EMAIL_PORT = 465
|
EMAIL_PORT = 465
|
||||||
EMAIL_HOST_USER = 'noreply@aduanasoft.com.mx'
|
EMAIL_HOST_USER = 'noreply@aduanasoft.com.mx'
|
||||||
EMAIL_HOST_PASSWORD = 'N036p7y!'
|
EMAIL_HOST_PASSWORD = os.getenv("pwd_email")
|
||||||
EMAIL_SUBJECT_PREFIX = 'AS Timbres'
|
|
||||||
EMAIL_USE_SSL=True
|
EMAIL_USE_SSL=True
|
||||||
|
|
||||||
|
|
||||||
@@ -126,7 +130,7 @@ if DEBUG:
|
|||||||
'ENGINE': 'django.db.backends.mysql',
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
'NAME': 'cfdi_as',
|
'NAME': 'cfdi_as',
|
||||||
'USER': 'root',
|
'USER': 'root',
|
||||||
'PASSWORD': 'Soluciones28@',
|
'PASSWORD':os.getenv("BD_PASS"),
|
||||||
'HOST': '127.0.0.1',
|
'HOST': '127.0.0.1',
|
||||||
'PORT': '',
|
'PORT': '',
|
||||||
'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
|
'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"},
|
||||||
@@ -170,7 +174,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
|
|
||||||
LANGUAGE_CODE = 'es-MX'
|
LANGUAGE_CODE = 'es-MX'
|
||||||
|
|
||||||
TIME_ZONE = 'CST6CDT'
|
TIME_ZONE = 'America/Chihuahua'
|
||||||
|
|
||||||
USE_I18N = True
|
USE_I18N = True
|
||||||
|
|
||||||
|
|||||||
@@ -9,12 +9,19 @@ from django.http import HttpResponse
|
|||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
from rest_framework.authtoken.views import obtain_auth_token
|
from rest_framework.authtoken.views import obtain_auth_token
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def response_error_handler(request, exception=None):
|
def response_error_handler(request, exception=None):
|
||||||
context={}
|
context={}
|
||||||
|
|
||||||
return render(request, '403.html',context,status=403)
|
return render(request, '403.html',context,status=403)
|
||||||
|
|
||||||
|
def response_error_handler_404(request,exception=None):
|
||||||
|
|
||||||
|
return render(request,'404.html',status=404)
|
||||||
|
|
||||||
def permission_denied_view(request):
|
def permission_denied_view(request):
|
||||||
|
|
||||||
raise PermissionDenied
|
raise PermissionDenied
|
||||||
|
|
||||||
|
|
||||||
@@ -24,23 +31,26 @@ 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('sistemas/',include('Sistemas.urls')),
|
||||||
path('403/', permission_denied_view),
|
path('403/', permission_denied_view),
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
]
|
]
|
||||||
handler403 = response_error_handler
|
handler403 = response_error_handler
|
||||||
|
handler404 = response_error_handler_404
|
||||||
|
|
||||||
|
|
||||||
if settings.DEBUG: #DEV only
|
if settings.DEBUG: #DEV only
|
||||||
urlpatterns += static(settings.STATIC_URL, document_root= settings.STATIC_ROOT)
|
urlpatterns += static(settings.STATIC_URL, document_root= settings.STATIC_ROOT)
|
||||||
urlpatterns += static(settings.MEDIA_URL, document_root= settings.MEDIA_ROOT)
|
urlpatterns += static(settings.MEDIA_URL, document_root= settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ROOT_URLCONF must specify the module that contains handler403 = ...
|
# ROOT_URLCONF must specify the module that contains handler403 = ...
|
||||||
@override_settings(ROOT_URLCONF=__name__)
|
@override_settings(ROOT_URLCONF=__name__)
|
||||||
class CustomErrorHandlerTests(SimpleTestCase):
|
class CustomErrorHandlerTests(SimpleTestCase):
|
||||||
|
|
||||||
def test_handler_renders_template_response(self):
|
def test_handler_renders_template_response(self):
|
||||||
response = self.client.get('/403/')
|
response = self.client.get('/403/')
|
||||||
|
|
||||||
# Make assertions on the response here. For example:
|
# Make assertions on the response here. For example:
|
||||||
self.assertContains(response, 'Error handler content', status_code=403)
|
self.assertContains(response, 'Error handler content', status_code=403)
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ from .models import Timbres, saldoModel, Clientes,ErroresTimbres
|
|||||||
|
|
||||||
class TimbresAdmin(admin.ModelAdmin):
|
class TimbresAdmin(admin.ModelAdmin):
|
||||||
list_display=['uuid','rfcc','rfcp','fecha','folio','serie','tipo','modo','created_at']
|
list_display=['uuid','rfcc','rfcp','fecha','folio','serie','tipo','modo','created_at']
|
||||||
|
list_filter=['modo','tipo']
|
||||||
|
|
||||||
|
|
||||||
class ClientesAdmin(admin.ModelAdmin):
|
class ClientesAdmin(admin.ModelAdmin):
|
||||||
list_display= ['RFC','Nombre','Activo','fecha_baja']
|
list_display= ['RFC','Nombre','Activo','fecha_baja']
|
||||||
|
list_filter =['RFC','Activo']
|
||||||
|
|
||||||
admin.site.register(Timbres,TimbresAdmin)
|
admin.site.register(Timbres,TimbresAdmin)
|
||||||
admin.site.register(saldoModel)
|
admin.site.register(saldoModel)
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
from functools import wraps
|
from functools import wraps
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.shortcuts import redirect
|
from django.shortcuts import redirect
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse, JsonResponse
|
||||||
|
from django.contrib.auth import authenticate, login
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
import base64
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
def Custom_is_staff_function(user):
|
def Custom_is_staff_function(user):
|
||||||
if user.is_staff:
|
if user.is_staff:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def is_staff_access(view_to_return="index"):
|
def is_staff_access(view_to_return="index"):
|
||||||
def decorator(view):
|
def decorator(view):
|
||||||
@wraps(view)
|
@wraps(view)
|
||||||
@@ -20,3 +21,37 @@ def is_staff_access(view_to_return="index"):
|
|||||||
return view(request, *args, **kwargs)
|
return view(request, *args, **kwargs)
|
||||||
return _wrapped_view
|
return _wrapped_view
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
#--------------------Auth basica
|
||||||
|
def auth_basic(request,*args, **kwargs):
|
||||||
|
if request.META['CONTENT_TYPE'] == 'application/json' and 'HTTP_AUTHORIZATION' in request.META.keys():
|
||||||
|
authmeth, auth = request.META['HTTP_AUTHORIZATION'].split(' ', 1)
|
||||||
|
if authmeth.lower() == 'token':
|
||||||
|
tokenA,user = auth.split(':', 1)
|
||||||
|
user = base64.b64decode(user)
|
||||||
|
user = user.decode('utf-8')
|
||||||
|
token = get_object_or_404(Token, key=tokenA)
|
||||||
|
if token and str(token.user)==user:
|
||||||
|
return True
|
||||||
|
#user= authenticate(username=token.user, password=pwd)
|
||||||
|
# print('user.is_authenticated',user.is_authenticated)
|
||||||
|
#if user.is_authenticated:
|
||||||
|
# return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
return False
|
||||||
|
elif request.META['CONTENT_TYPE'] == 'application/json' and 'HTTP_AUTHORIZATION' not in request.META.keys():
|
||||||
|
return request.user.is_authenticated
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def http_basic_auth():
|
||||||
|
def decorator(view):
|
||||||
|
@wraps(view)
|
||||||
|
def _wrapped_view(request,*args, **kwargs):
|
||||||
|
if not auth_basic(request,*args, **kwargs):
|
||||||
|
return JsonResponse({'Error':'las credenciales Token:user(base64) son incorrectas.'},status=401)
|
||||||
|
return view(request, *args, **kwargs)
|
||||||
|
return _wrapped_view
|
||||||
|
return decorator
|
||||||
@@ -40,33 +40,32 @@ class Clientes(models.Model):
|
|||||||
fecha_baja = models.DateField(blank=True,null=True)
|
fecha_baja = models.DateField(blank=True,null=True)
|
||||||
email = models.EmailField(max_length=254, blank=True)
|
email = models.EmailField(max_length=254, blank=True)
|
||||||
conteo_mes = models.IntegerField(blank=True,null=True,default=0)
|
conteo_mes = models.IntegerField(blank=True,null=True,default=0)
|
||||||
def timbres_X_MES(self, mes):
|
def timbres_X_MES(self, mes=None, year=None, PAC=None):
|
||||||
|
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
|
if year is None:
|
||||||
year = today.year
|
year = today.year
|
||||||
|
|
||||||
if mes==None:
|
if mes==None:
|
||||||
mes = today.month
|
mes = today.month
|
||||||
|
|
||||||
dat = datetime.datetime(int(year),int(mes),1)
|
dat = datetime.datetime(int(year),int(mes),1)
|
||||||
if dat.month in (1,3,5,7,8,10,12):#31
|
if dat.month in (1,3,5,7,8,10,12):#31
|
||||||
findate = dat + datetime.timedelta(days=30)
|
findate = dat + datetime.timedelta(days=30)
|
||||||
#findate += datetime.timedelta(days=0)
|
|
||||||
elif dat.month in (4,6,9,11):#30
|
|
||||||
|
|
||||||
|
elif dat.month in (4,6,9,11):#30
|
||||||
findate = dat + datetime.timedelta(days=29)
|
findate = dat + datetime.timedelta(days=29)
|
||||||
#findate += datetime.timedelta(days=0)
|
|
||||||
else:#28 or 29
|
else:#28 or 29
|
||||||
findate = dat + datetime.timedelta(days=28)
|
findate = dat + datetime.timedelta(days=28)
|
||||||
findate += datetime.timedelta(days=1)
|
findate += datetime.timedelta(days=1)
|
||||||
#print(f'dat {(dat)} fdate={findate}')
|
if PAC:
|
||||||
|
cou = Timbres.objects.filter(rfcc=self.RFC, created_at__range=[dat,findate], rfcp=PAC).count()
|
||||||
|
else:
|
||||||
cou = Timbres.objects.filter(rfcc=self.RFC, created_at__range=[dat,findate]).count()
|
cou = Timbres.objects.filter(rfcc=self.RFC, created_at__range=[dat,findate]).count()
|
||||||
|
|
||||||
self.conteo_mes =cou
|
self.conteo_mes =cou
|
||||||
self.save()
|
self.save()
|
||||||
return cou
|
|
||||||
@property
|
@property
|
||||||
def timbres_mes_count(self):
|
def timbres_mes_count(self):
|
||||||
|
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
month = today.month
|
month = today.month
|
||||||
year = today.year
|
year = today.year
|
||||||
@@ -74,15 +73,6 @@ class Clientes(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('-Activo','-conteo_mes','RFC')
|
ordering = ('-Activo','-conteo_mes','RFC')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
class Maquinas_Conectadas(models.Model):
|
return self.Nombre
|
||||||
UserName = models.CharField(max_length=255)
|
|
||||||
PC_Name = models.CharField(max_length=255)
|
|
||||||
Is64 = models.BooleanField()
|
|
||||||
OSversion= models.CharField(max_length=255)
|
|
||||||
local_ip = models.CharField(max_length=55)
|
|
||||||
public_ip= models.CharField(max_length=55)
|
|
||||||
RFC = models.CharField(max_length=13)
|
|
||||||
class Meta:
|
|
||||||
abstract =True
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import requests
|
import requests
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
from .models import saldoModel
|
from .models import saldoModel
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,56 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
# Create your tests here.
|
from django.contrib.auth.models import User
|
||||||
|
from .models import Clientes
|
||||||
|
|
||||||
|
class ClientesTests(TestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
test_user = User.objects.create_user(username='testuser1',password='Soluciones28@')
|
||||||
|
test_user.save()
|
||||||
|
|
||||||
|
cls.cliente = Clientes.objects.create(
|
||||||
|
RFC="SCT050708EB2",
|
||||||
|
Nombre="Aduanasoft",
|
||||||
|
Activo=True,
|
||||||
|
#fecha_baja="2022-12-20",
|
||||||
|
email="fjrodriguez28@gmail.com",
|
||||||
|
conteo_mes=12,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_redirect_if_not_logged_in(self):
|
||||||
|
response = self.client.get(reverse('index'))
|
||||||
|
self.assertRedirects(response, '/accounts/login/?next=/')
|
||||||
|
|
||||||
|
def test_cliente_content(self):
|
||||||
|
self.assertEqual(self.cliente.RFC,"SCT050708EB2")
|
||||||
|
self.assertEqual(self.cliente.Nombre,"Aduanasoft")
|
||||||
|
self.assertEqual(self.cliente.Activo,True)
|
||||||
|
#self.assertEqual(self.cliente.fecha_baja,"2022-12-20")
|
||||||
|
self.assertEqual(self.cliente.email,"fjrodriguez28@gmail.com")
|
||||||
|
self.assertEqual(self.cliente.conteo_mes,12)
|
||||||
|
|
||||||
|
#test for login user view and contains client with RFC SCT...
|
||||||
|
def test_cliente_login_cliente_listview(self):
|
||||||
|
login = self.client.login(username='testuser1',password='Soluciones28@')
|
||||||
|
response = self.client.get(reverse('index'))
|
||||||
|
|
||||||
|
self.assertEqual(str(response.context['user']), 'testuser1')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code,200)
|
||||||
|
self.assertContains(response, "SCT050708EB2")
|
||||||
|
self.assertTemplateUsed(response, "Clientes/index.html")
|
||||||
|
|
||||||
|
#---------------_APIs Views Tests
|
||||||
|
from rest_framework import status
|
||||||
|
from rest_framework.test import APITestCase, APIClient
|
||||||
|
|
||||||
|
class APITests(APITestCase):
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_api_check_RFC(self):
|
||||||
|
pass
|
||||||
@@ -4,8 +4,12 @@ from .views import (
|
|||||||
timbres_cliente,
|
timbres_cliente,
|
||||||
ClientesUpdateView,
|
ClientesUpdateView,
|
||||||
ClientesCreateView,
|
ClientesCreateView,
|
||||||
|
ErroresTimbresListView,
|
||||||
export_Excel,
|
export_Excel,
|
||||||
send_timbres_Email,
|
send_timbres_Email,
|
||||||
|
Retrive_Cliente_Email,
|
||||||
|
PACS_Retrive_RFCS,
|
||||||
|
|
||||||
|
|
||||||
#API DRF
|
#API DRF
|
||||||
saldo_funct2,
|
saldo_funct2,
|
||||||
@@ -20,10 +24,12 @@ urlpatterns = [
|
|||||||
path('timbres_cliente/<str:RFC>/', timbres_cliente, name='timbres_cliente'),
|
path('timbres_cliente/<str:RFC>/', timbres_cliente, name='timbres_cliente'),
|
||||||
path('cliente/update/<int:pk>/',ClientesUpdateView.as_view(),name='update_cliente'),
|
path('cliente/update/<int:pk>/',ClientesUpdateView.as_view(),name='update_cliente'),
|
||||||
path('cliente/add/', ClientesCreateView.as_view(), name='add_cliente'),
|
path('cliente/add/', ClientesCreateView.as_view(), name='add_cliente'),
|
||||||
|
path('errores/timbres/list/', ErroresTimbresListView.as_view(), name='ErroresTimbresList'),
|
||||||
path('get_timbres_xls/', export_Excel, name='export_Excel'),
|
path('get_timbres_xls/', export_Excel, name='export_Excel'),
|
||||||
path('send_timbres_cliente/',send_timbres_Email, name='send_timbres_Email'),
|
path('send_timbres_cliente/',send_timbres_Email, name='send_timbres_Email'),
|
||||||
path('getActivoRFC/', check_RFC.as_view(), name='check_active_RFC'),
|
path('getActivoRFC/', check_RFC.as_view(), name='check_active_RFC'),
|
||||||
path('get_saldo2/', saldo_funct2.as_view(), name='saldo_funct2'),
|
path('get_saldo2/', saldo_funct2.as_view(), name='saldo_funct2'),
|
||||||
path('check_host/',check_host.as_view(),name='check_host'),
|
path('check_host/',check_host.as_view(),name='check_host'),
|
||||||
|
path('emails_cliente/',Retrive_Cliente_Email, name='Retrive_Cliente_Email'),
|
||||||
|
path('pacs/list/',PACS_Retrive_RFCS,name='PACS_Retrive_RFCS'),
|
||||||
]
|
]
|
||||||
@@ -1,26 +1,33 @@
|
|||||||
|
import os
|
||||||
|
import re
|
||||||
|
import datetime
|
||||||
|
import functools
|
||||||
|
|
||||||
|
from asgiref.sync import sync_to_async
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.files.storage import FileSystemStorage
|
||||||
from django.shortcuts import render,redirect
|
from django.shortcuts import render,redirect
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse,JsonResponse
|
||||||
from django.http import JsonResponse
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from .custom_decorators import is_staff_access
|
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
||||||
|
from django.db.models import Q
|
||||||
|
from django.views.generic.edit import CreateView,UpdateView
|
||||||
|
from django.views.generic.list import ListView
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||||
|
|
||||||
|
from .custom_decorators import is_staff_access, http_basic_auth
|
||||||
from .models import Clientes,Timbres,saldoModel,ErroresTimbres
|
from .models import Clientes,Timbres,saldoModel,ErroresTimbres
|
||||||
|
from .serailizers import ClienteSerializer
|
||||||
|
from .forms import ClienteForm,EmailForm
|
||||||
|
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
from Sistemas.permissions import ItsAdminToken
|
||||||
|
|
||||||
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
||||||
from django.db.models import Q
|
|
||||||
import datetime
|
|
||||||
from django.views.generic.edit import CreateView,UpdateView
|
|
||||||
from .forms import ClienteForm,EmailForm
|
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
|
||||||
from asgiref.sync import sync_to_async
|
|
||||||
from django.shortcuts import get_object_or_404
|
|
||||||
from .serailizers import ClienteSerializer
|
|
||||||
#EXCEL
|
#EXCEL
|
||||||
from openpyxl import Workbook
|
from openpyxl import Workbook
|
||||||
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
||||||
@@ -29,32 +36,26 @@ from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
|||||||
from django.core.mail import EmailMessage
|
from django.core.mail import EmailMessage
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
import functools
|
|
||||||
|
|
||||||
from django.core.files.storage import FileSystemStorage
|
|
||||||
import os
|
|
||||||
from django.conf import settings
|
|
||||||
import re
|
|
||||||
|
|
||||||
def read_env_file():
|
def read_env_file():
|
||||||
try:
|
try:
|
||||||
#env_file = os.listdir(settings.BASE_DIR)
|
#env_file = os.listdir(settings.BASE_DIR)
|
||||||
storage = FileSystemStorage(location=settings.BASE_DIR)
|
storage = FileSystemStorage(location=settings.BASE_DIR)
|
||||||
env_file= os.path.join(settings.BASE_DIR,'.env')
|
env_file= os.path.join(settings.BASE_DIR,'.env')
|
||||||
print('EEEEE: ', env_file)
|
|
||||||
|
|
||||||
lista =['asds', 'asdasd','sss','com' ,'pol.com']
|
lista =['asds', 'asdasd','sss','com' ,'pol.com']
|
||||||
if storage.exists(env_file):
|
if storage.exists(env_file):
|
||||||
with open(env_file, 'r') as file:
|
with open(env_file, 'r') as file:
|
||||||
data = file.read()
|
data = file.read()
|
||||||
data =re.findall('"([^"]*)"',data)
|
data =re.findall('"([^"]*)"',data)
|
||||||
print('data',data)
|
|
||||||
|
|
||||||
for x in lista:
|
for x in lista:
|
||||||
data.append(x)
|
data.append(x)
|
||||||
res= ' '.join(data)
|
res= ' '.join(data)
|
||||||
final = '"'+res+'"'
|
final = '"'+res+'"'
|
||||||
print('final',final)
|
|
||||||
with open(env_file, 'w') as newFile:
|
with open(env_file, 'w') as newFile:
|
||||||
newFile.write("export hosts="+final)
|
newFile.write("export hosts="+final)
|
||||||
except:
|
except:
|
||||||
@@ -62,6 +63,7 @@ def read_env_file():
|
|||||||
|
|
||||||
@sync_to_async(thread_sensitive=False)
|
@sync_to_async(thread_sensitive=False)
|
||||||
@login_required
|
@login_required
|
||||||
|
@is_staff_access()
|
||||||
def send_timbres_Email(request):
|
def send_timbres_Email(request):
|
||||||
req = request.method
|
req = request.method
|
||||||
|
|
||||||
@@ -71,6 +73,7 @@ def send_timbres_Email(request):
|
|||||||
messages.add_message(request, messages.ERROR, f'{form.errors}')
|
messages.add_message(request, messages.ERROR, f'{form.errors}')
|
||||||
return redirect('index')
|
return redirect('index')
|
||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
|
|
||||||
year = today.year
|
year = today.year
|
||||||
|
|
||||||
RFC = request.GET.get('RFC', None) if req=='GET' else form.cleaned_data["RFC"]
|
RFC = request.GET.get('RFC', None) if req=='GET' else form.cleaned_data["RFC"]
|
||||||
@@ -98,7 +101,7 @@ def send_timbres_Email(request):
|
|||||||
else:
|
else:
|
||||||
findate = dat+datetime.timedelta(days=28)
|
findate = dat+datetime.timedelta(days=28)
|
||||||
findate +=datetime.timedelta(days=1)
|
findate +=datetime.timedelta(days=1)
|
||||||
print(f'dat{dat} findate:{findate}')
|
|
||||||
if mes is not None and RFC is not None:
|
if mes is not None and RFC is not None:
|
||||||
objeto_a_trabajar = Timbres.objects.filter(rfcc=RFC, created_at__range=[dat,findate])
|
objeto_a_trabajar = Timbres.objects.filter(rfcc=RFC, created_at__range=[dat,findate])
|
||||||
else:
|
else:
|
||||||
@@ -162,28 +165,47 @@ def send_timbres_Email(request):
|
|||||||
def index(request):
|
def index(request):
|
||||||
#read_env_file()
|
#read_env_file()
|
||||||
clientes_list = Clientes.objects.all()
|
clientes_list = Clientes.objects.all()
|
||||||
|
PAC = request.GET.get('PAC',None)
|
||||||
mes = request.GET.get('mes', None)
|
mes = request.GET.get('mes', None)
|
||||||
|
today = datetime.date.today()
|
||||||
|
|
||||||
|
year = request.GET.get('year',None)
|
||||||
|
if year is None or year =='None':
|
||||||
|
year= today.year
|
||||||
|
if mes is None or mes =='None':
|
||||||
|
mes = today.month
|
||||||
page = request.GET.get('page', 1)
|
page = request.GET.get('page', 1)
|
||||||
search = request.GET.get('search',None)
|
search = request.GET.get('search',None)
|
||||||
rfcc = request.GET.get('rfcc', None)
|
rfcc = request.GET.get('rfcc', None)
|
||||||
filters = {key:value[0] for (key,value) in dict(request.GET).items() if value !=[""]}
|
filters = {key:value[0] for (key,value) in dict(request.GET).items() if value !=[""] or value!=None}
|
||||||
filters.pop('page', '')
|
filters.pop('page', '')
|
||||||
filters.pop('datepicker','')
|
filters.pop('datepicker','')
|
||||||
filters.pop('datepickerFin','')
|
filters.pop('datepickerFin','')
|
||||||
print('filters------',filters)
|
filters.pop('mes','')
|
||||||
if rfcc:
|
filters.pop('year','')
|
||||||
|
if PAC=='00':
|
||||||
|
filters.pop('PAC')
|
||||||
|
PAC=None
|
||||||
|
|
||||||
|
if rfcc and search:
|
||||||
clientes_list = Clientes.objects.filter(Q(RFC__icontains=search))
|
clientes_list = Clientes.objects.filter(Q(RFC__icontains=search))
|
||||||
for i,ii in enumerate(clientes_list):
|
|
||||||
ii.timbres_X_MES(mes=mes)
|
met = iter(clientes_list)
|
||||||
|
while met:
|
||||||
|
try:
|
||||||
|
c = next(met)
|
||||||
|
c.timbres_X_MES(mes=mes,year=year, PAC=PAC)
|
||||||
|
except StopIteration:
|
||||||
|
break
|
||||||
|
|
||||||
clientes_list =pageFunc(page,clientes_list,20)
|
clientes_list =pageFunc(page,clientes_list,20)
|
||||||
|
|
||||||
filters.pop('mes','')
|
|
||||||
context = {
|
context = {
|
||||||
'lista':clientes_list,
|
'lista':clientes_list,
|
||||||
'mes':mes,
|
'mes':mes,
|
||||||
|
'year':year,
|
||||||
'filters':filters,
|
'filters':filters,
|
||||||
'emailForm':EmailForm(),
|
'emailForm':EmailForm(),
|
||||||
|
|
||||||
}
|
}
|
||||||
return render(request,'Clientes/index.html',context)
|
return render(request,'Clientes/index.html',context)
|
||||||
|
|
||||||
@@ -207,40 +229,68 @@ def timbres_cliente(request, RFC):
|
|||||||
else:
|
else:
|
||||||
lista = Timbres.objects.filter(rfcc=RFC,modo='Normal')
|
lista = Timbres.objects.filter(rfcc=RFC,modo='Normal')
|
||||||
|
|
||||||
PAC= request.GET.get('PAC',None)
|
mes = request.GET.get('mes', None)
|
||||||
if PAC=='01':
|
year = request.GET.get('year',None)
|
||||||
lista = lista.filter(rfcp='EME000602QR9')
|
|
||||||
if PAC=='02':
|
if year is None or year=='':
|
||||||
lista = lista.exclude(rfcp='EME000602QR9')
|
today= datetime.date.today()
|
||||||
|
year =today.year
|
||||||
|
|
||||||
search = request.GET.get('search',None)
|
search = request.GET.get('search',None)
|
||||||
page = request.GET.get('page', 1)
|
page = request.GET.get('page', 1)
|
||||||
datepicker = request.GET.get('datepicker', None)
|
datepicker = request.GET.get('datepicker', None)
|
||||||
datepickerFin = request.GET.get('datepickerFin', None)
|
datepickerFin = request.GET.get('datepickerFin', None)
|
||||||
tipo = request.GET.get('tipo',None)
|
tipo = request.GET.get('tipo',None)
|
||||||
|
PAC= request.GET.get('PAC',None)
|
||||||
|
|
||||||
|
if PAC is not None and PAC !='00':
|
||||||
|
lista = lista.filter(rfcp=PAC)
|
||||||
|
|
||||||
filters = {key:value[0] for (key,value) in dict(request.GET).items() if value !=[""]}
|
filters = {key:value[0] for (key,value) in dict(request.GET).items() if value !=[""]}
|
||||||
|
|
||||||
filters.pop('page', '')
|
filters.pop('page', '')
|
||||||
filters.pop('PAC', '')
|
if 'PAC' not in filters:
|
||||||
|
filters['PAC']='00'
|
||||||
|
if 'mes' not in filters:
|
||||||
|
filters['mes']='00'
|
||||||
|
|
||||||
|
if tipo and search is not None:
|
||||||
if tipo:
|
|
||||||
lista = lista.filter(Q(tipo__icontains=search))
|
lista = lista.filter(Q(tipo__icontains=search))
|
||||||
|
|
||||||
if datepicker and datepickerFin:
|
if datepicker and datepickerFin:
|
||||||
inicio = [int(i) for i in datepicker.split("/")]
|
# inicio = [int(i) for i in datepicker.split("/")]
|
||||||
fin = [int(i) for i in datepickerFin.split("/")]
|
# fin = [int(i) for i in datepickerFin.split("/")]
|
||||||
#print('inicio',inicio,' fin',fin)
|
inicio = [int(i) for i in datepicker.split("-")]
|
||||||
|
fin = [int(i) for i in datepickerFin.split("-")]
|
||||||
|
|
||||||
|
#start = datetime.datetime(inicio[2],inicio[0],inicio[1])
|
||||||
|
start = datetime.datetime(inicio[0],inicio[1],inicio[2])
|
||||||
|
|
||||||
start = datetime.datetime(inicio[2],inicio[0],inicio[1])
|
|
||||||
start += datetime.timedelta(days=0)
|
start += datetime.timedelta(days=0)
|
||||||
end = datetime.datetime(fin[2],fin[0],fin[1])
|
# end = datetime.datetime(fin[2],fin[0],fin[1])
|
||||||
|
end = datetime.datetime(fin[0],fin[1],fin[2])
|
||||||
|
|
||||||
end += datetime.timedelta(days=1)
|
end += datetime.timedelta(days=1)
|
||||||
#datetime.date.today()
|
|
||||||
#print('FECHA',datetime.datetime.today(), 'HORA')
|
|
||||||
print('start',start, 'end',end)
|
|
||||||
lista = lista.filter(created_at__range=[start, end])
|
lista = lista.filter(created_at__range=[start, end])
|
||||||
|
|
||||||
|
if mes is None or mes =='None' or mes=='':
|
||||||
|
mes='00' #Todos
|
||||||
|
|
||||||
|
if mes != '00':
|
||||||
|
|
||||||
|
dat = datetime.datetime(int(year), int(mes),1)
|
||||||
|
if dat.month in(1,3,5,7,8,10,12):
|
||||||
|
findate = dat+datetime.timedelta(days=30)
|
||||||
|
elif dat.month in (4,6,9,11):
|
||||||
|
findate = dat+datetime.timedelta(days=29)
|
||||||
|
else:
|
||||||
|
findate = dat+datetime.timedelta(days=28)
|
||||||
|
findate +=datetime.timedelta(days=1)
|
||||||
|
lista = lista.filter(created_at__range=[dat,findate])
|
||||||
|
else:
|
||||||
|
lista = lista.filter(created_at__year=int(year))
|
||||||
|
|
||||||
conteo = lista.count()
|
conteo = lista.count()
|
||||||
|
|
||||||
lista =pageFunc(page,lista,50)
|
lista =pageFunc(page,lista,50)
|
||||||
@@ -256,6 +306,7 @@ def timbres_cliente(request, RFC):
|
|||||||
|
|
||||||
@sync_to_async(thread_sensitive=False)
|
@sync_to_async(thread_sensitive=False)
|
||||||
@login_required
|
@login_required
|
||||||
|
@is_staff_access()
|
||||||
def export_Excel(request):
|
def export_Excel(request):
|
||||||
|
|
||||||
RFC = request.GET.get('RFC', None)
|
RFC = request.GET.get('RFC', None)
|
||||||
@@ -265,7 +316,7 @@ def export_Excel(request):
|
|||||||
month = today.month
|
month = today.month
|
||||||
year = today.year
|
year = today.year
|
||||||
|
|
||||||
if mes is None or mes =='None':
|
if mes is None or mes =='None' or mes=='':
|
||||||
mes = month
|
mes = month
|
||||||
|
|
||||||
dat =datetime.datetime(int(year), int(mes),1)
|
dat =datetime.datetime(int(year), int(mes),1)
|
||||||
@@ -277,7 +328,7 @@ def export_Excel(request):
|
|||||||
else:
|
else:
|
||||||
findate = dat+datetime.timedelta(days=28)
|
findate = dat+datetime.timedelta(days=28)
|
||||||
findate +=datetime.timedelta(days=1)
|
findate +=datetime.timedelta(days=1)
|
||||||
print(f'dat{dat} findate:{findate}')
|
|
||||||
if mes is not None and RFC is not None:
|
if mes is not None and RFC is not None:
|
||||||
objeto_a_trabajar = Timbres.objects.filter(rfcc=RFC, created_at__range=[dat,findate])
|
objeto_a_trabajar = Timbres.objects.filter(rfcc=RFC, created_at__range=[dat,findate])
|
||||||
else:
|
else:
|
||||||
@@ -285,8 +336,6 @@ def export_Excel(request):
|
|||||||
for i,ii in enumerate(objeto_a_trabajar):
|
for i,ii in enumerate(objeto_a_trabajar):
|
||||||
ii.timbres_X_MES(mes=mes )
|
ii.timbres_X_MES(mes=mes )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
wb = Workbook()
|
wb = Workbook()
|
||||||
ws = wb.active
|
ws = wb.active
|
||||||
|
|
||||||
@@ -312,28 +361,58 @@ def export_Excel(request):
|
|||||||
contenido = "attachment; filename = {0}".format(nombre_archivo)
|
contenido = "attachment; filename = {0}".format(nombre_archivo)
|
||||||
response["Content-Disposition"] = contenido
|
response["Content-Disposition"] = contenido
|
||||||
wb.save( response)
|
wb.save( response)
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
@http_basic_auth()
|
||||||
|
def Retrive_Cliente_Email(request):
|
||||||
|
if request.method == 'GET':
|
||||||
|
clientes = list(Clientes.objects.values('email').filter(RFC=request.GET.get('RFC',None)))
|
||||||
|
return JsonResponse({'data':clientes})
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
#@is_staff_access()
|
||||||
|
def PACS_Retrive_RFCS(request):
|
||||||
|
timbres = {}
|
||||||
|
status = 200
|
||||||
|
if request.method == 'GET':
|
||||||
|
RFC= request.GET.get('RFC','')
|
||||||
|
|
||||||
|
if RFC !='':
|
||||||
|
timbres =list(Timbres.objects.values('rfcp').filter(rfcc__in=[RFC]))
|
||||||
|
else:
|
||||||
|
timbres =list(Timbres.objects.values('rfcp').filter(rfcp__isnull=False))
|
||||||
|
else:
|
||||||
|
status=403
|
||||||
|
return JsonResponse({'PACS':timbres},status=status)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#-----------------------------------API VIEWS
|
#-----------------------------------API VIEWS
|
||||||
#--------------------------------------------
|
#--------------------------------------------
|
||||||
|
|
||||||
class check_RFC(APIView):
|
class check_RFC(APIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (ItsAdminToken,IsAuthenticated,)
|
||||||
def get(self,request):
|
def get(self,request):
|
||||||
rfc = request.GET.get('RFC', None)
|
rfc = request.GET.get('RFC', None)
|
||||||
|
try:
|
||||||
|
if rfc is None or len(rfc)==0:
|
||||||
|
return Response({'Error': 'RFC parameter cannot be empty', 'isError': True})
|
||||||
|
|
||||||
cliente, created = Clientes.objects.get_or_create(RFC=rfc)
|
cliente, created = Clientes.objects.get_or_create(RFC=rfc)
|
||||||
|
serializer = ClienteSerializer(cliente)
|
||||||
if created:
|
if created:
|
||||||
cliente.Activo=True
|
cliente.Activo=True
|
||||||
cliente.save()
|
cliente.save()
|
||||||
#cliente = get_object_or_404(Clientes, RFC=rfc)
|
|
||||||
serializer = ClienteSerializer(cliente)
|
if not serializer.is_valid:
|
||||||
|
return Response({'Error':f'{serializer.errors}','isError':True},status=200)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
except Exception as E:
|
||||||
|
return Response({'Error':f'check_RFC:{E} RFC:{rfc}','isError':True})
|
||||||
|
|
||||||
class add_timbre2(APIView):
|
class add_timbre2(APIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (ItsAdminToken,IsAuthenticated,)
|
||||||
def get(self,request):
|
def get(self,request):
|
||||||
|
|
||||||
uuid= request.GET.get('uuid', None)
|
uuid= request.GET.get('uuid', None)
|
||||||
rfcc= request.GET.get('rfcc', None)
|
rfcc= request.GET.get('rfcc', None)
|
||||||
fecha=request.GET.get('fecha', None)
|
fecha=request.GET.get('fecha', None)
|
||||||
@@ -342,16 +421,8 @@ class add_timbre2(APIView):
|
|||||||
tipo=request.GET.get('tipo', None)
|
tipo=request.GET.get('tipo', None)
|
||||||
rfcp=request.GET.get('rfcp', None)
|
rfcp=request.GET.get('rfcp', None)
|
||||||
modo=request.GET.get('modo', None)
|
modo=request.GET.get('modo', None)
|
||||||
|
obj={'uuid':uuid,'rfcc':rfcc,'fecha':fecha,'folio':folio,
|
||||||
obj={
|
'serie':serie,'tipo':tipo,'rfcp':rfcp,'modo':modo
|
||||||
'uuid':uuid,
|
|
||||||
'rfcc':rfcc,
|
|
||||||
'fecha':fecha,
|
|
||||||
'folio':folio,
|
|
||||||
'serie':serie,
|
|
||||||
'tipo':tipo,
|
|
||||||
'rfcp':rfcp,
|
|
||||||
'modo':modo
|
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
obj = Timbres.objects.create(**obj)
|
obj = Timbres.objects.create(**obj)
|
||||||
@@ -364,10 +435,10 @@ class add_timbre2(APIView):
|
|||||||
folio=folio,
|
folio=folio,
|
||||||
modo=modo
|
modo=modo
|
||||||
)
|
)
|
||||||
return Response({'fok':f'{e}'})
|
return Response({'Error':f'{e}'})
|
||||||
|
|
||||||
class saldo_funct2(APIView):
|
class saldo_funct2(APIView):
|
||||||
permission_classes =(IsAuthenticated,)
|
permission_classes =(ItsAdminToken,IsAuthenticated,)
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
timbres = request.GET.get('num',None)
|
timbres = request.GET.get('num',None)
|
||||||
try:
|
try:
|
||||||
@@ -381,15 +452,19 @@ class saldo_funct2(APIView):
|
|||||||
return Response(content)
|
return Response(content)
|
||||||
|
|
||||||
class check_host(APIView):
|
class check_host(APIView):
|
||||||
permission_classes = (IsAuthenticated,)
|
permission_classes = (ItsAdminToken,IsAuthenticated,)
|
||||||
|
|
||||||
def post(self,request, format=None):
|
def post(self,request, format=None):
|
||||||
data = request.data
|
data = request.data
|
||||||
print(data)
|
|
||||||
return Response(data)
|
return Response(data)
|
||||||
|
|
||||||
#---------------------------CLASS BASED VIEWS
|
#---------------------------CLASS BASED VIEWS
|
||||||
#--------------------------------------------
|
#--------------------------------------------
|
||||||
|
class ErroresTimbresListView(LoginRequiredMixin,ListView):
|
||||||
|
model = ErroresTimbres
|
||||||
|
paginate_by = 100
|
||||||
|
template_name = 'Clientes/Errores_Timbres_list.html'
|
||||||
|
|
||||||
class ClientesUpdateView(UserPassesTestMixin,LoginRequiredMixin,UpdateView):
|
class ClientesUpdateView(UserPassesTestMixin,LoginRequiredMixin,UpdateView):
|
||||||
model= Clientes
|
model= Clientes
|
||||||
form_class=ClienteForm
|
form_class=ClienteForm
|
||||||
@@ -397,13 +472,11 @@ class ClientesUpdateView(UserPassesTestMixin,LoginRequiredMixin,UpdateView):
|
|||||||
template_name='Clientes/edit_cliente.html'
|
template_name='Clientes/edit_cliente.html'
|
||||||
|
|
||||||
def test_func(self):
|
def test_func(self):
|
||||||
|
|
||||||
res = self.request.user.groups.filter(name= 'admin_soft')
|
res = self.request.user.groups.filter(name= 'admin_soft')
|
||||||
if not res:
|
if not res:
|
||||||
messages.error(self.request, f'Lo sentimos. La página que buscas no está disponible, no cuentas con los permisos.')
|
messages.error(self.request, f'Lo sentimos. La página que buscas no está disponible, no cuentas con los permisos.')
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
class ClientesCreateView(UserPassesTestMixin,LoginRequiredMixin,CreateView):
|
class ClientesCreateView(UserPassesTestMixin,LoginRequiredMixin,CreateView):
|
||||||
model = Clientes
|
model = Clientes
|
||||||
form_class = ClienteForm
|
form_class = ClienteForm
|
||||||
|
|||||||
0
Sistemas/__init__.py
Normal file
0
Sistemas/__init__.py
Normal file
28
Sistemas/admin.py
Normal file
28
Sistemas/admin.py
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
from .models import Sistema, sistemas_por_cliente, Device,DeviceHistory
|
||||||
|
# Register your models here.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Sistema_Admin(admin.ModelAdmin):
|
||||||
|
def NSistema(self,obj):
|
||||||
|
return obj.nombre_sistema
|
||||||
|
list_display = ['NSistema']
|
||||||
|
|
||||||
|
class SPC(admin.ModelAdmin):
|
||||||
|
'''Sistemas Por Cliente'''
|
||||||
|
def Cliente(self,obj):
|
||||||
|
return obj
|
||||||
|
list_display = ['id_sistema','Cliente','num_licencias']
|
||||||
|
|
||||||
|
class DeviceHistoryAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['device','first_authentication', 'last_authentication']
|
||||||
|
|
||||||
|
class DeviceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['client', 'device_name', 'ip_address', 'sistema', 'macAddress']
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.register(Sistema,Sistema_Admin)
|
||||||
|
admin.site.register(sistemas_por_cliente,SPC)
|
||||||
|
admin.site.register(Device,DeviceAdmin)
|
||||||
|
admin.site.register(DeviceHistory,DeviceHistoryAdmin)
|
||||||
6
Sistemas/apps.py
Normal file
6
Sistemas/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SistemasConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'Sistemas'
|
||||||
32
Sistemas/migrations/0001_initial.py
Normal file
32
Sistemas/migrations/0001_initial.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-19 19:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Clientes', '0014_alter_clientes_options'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Sistema',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('nombre_sistema', models.CharField(max_length=100, unique=True)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='sistemas_por_cliente',
|
||||||
|
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', to='Clientes.clientes')),
|
||||||
|
('id_sistema', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sistema_spc', to='Sistemas.sistema')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 15:37
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Clientes', '0014_alter_clientes_options'),
|
||||||
|
('Sistemas', '0001_initial'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Device',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('password', models.CharField(max_length=128, verbose_name='password')),
|
||||||
|
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
||||||
|
('device_name', models.CharField(max_length=255)),
|
||||||
|
('device_os', models.CharField(max_length=255)),
|
||||||
|
('ip_address', models.GenericIPAddressField()),
|
||||||
|
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Clientes.clientes')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AlterModelOptions(
|
||||||
|
name='sistemas_por_cliente',
|
||||||
|
options={'ordering': ('-cliente', 'id_sistema')},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='DeviceHistory',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('first_authentication', models.DateTimeField(auto_now_add=True)),
|
||||||
|
('last_authentication', models.DateTimeField(auto_now=True)),
|
||||||
|
('ip_address', models.GenericIPAddressField()),
|
||||||
|
('device', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Sistemas.device')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
]
|
||||||
26
Sistemas/migrations/0003_device_token_device_username.py
Normal file
26
Sistemas/migrations/0003_device_token_device_username.py
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:18
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authtoken', '0003_tokenproxy'),
|
||||||
|
('Sistemas', '0002_device_alter_sistemas_por_cliente_options_and_more'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='token',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='authtoken.token'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='username',
|
||||||
|
field=models.CharField(default=1, max_length=150, unique=True),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
||||||
21
Sistemas/migrations/0004_alter_device_username.py
Normal file
21
Sistemas/migrations/0004_alter_device_username.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:22
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('Sistemas', '0003_device_token_device_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='device',
|
||||||
|
name='username',
|
||||||
|
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-23 17:39
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0004_alter_device_username'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='device',
|
||||||
|
name='last_login',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='device',
|
||||||
|
name='password',
|
||||||
|
),
|
||||||
|
]
|
||||||
19
Sistemas/migrations/0006_device_sistema.py
Normal file
19
Sistemas/migrations/0006_device_sistema.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-25 13:59
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0005_remove_device_last_login_remove_device_password'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='sistema',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='Sistemas.sistemas_por_cliente'),
|
||||||
|
),
|
||||||
|
]
|
||||||
19
Sistemas/migrations/0007_alter_device_sistema.py
Normal file
19
Sistemas/migrations/0007_alter_device_sistema.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-25 14:33
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0006_device_sistema'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='device',
|
||||||
|
name='sistema',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='Sistemas.sistema'),
|
||||||
|
),
|
||||||
|
]
|
||||||
18
Sistemas/migrations/0008_device_macaddress.py
Normal file
18
Sistemas/migrations/0008_device_macaddress.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.3 on 2023-01-25 18:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('Sistemas', '0007_alter_device_sistema'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='macAddress',
|
||||||
|
field=models.CharField(blank=True, max_length=30, null=True, unique=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
0
Sistemas/migrations/__init__.py
Normal file
0
Sistemas/migrations/__init__.py
Normal file
111
Sistemas/models.py
Normal file
111
Sistemas/models.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
from django.db import models
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from Clientes.models import Clientes
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from django.contrib.auth.models import BaseUserManager
|
||||||
|
|
||||||
|
import re
|
||||||
|
|
||||||
|
class Sistema(models.Model):
|
||||||
|
nombre_sistema= models.CharField(max_length=100, blank=False,null=False,unique=True)
|
||||||
|
# class Meta:
|
||||||
|
# abstract=True
|
||||||
|
def __str__(self):
|
||||||
|
return self.nombre_sistema
|
||||||
|
|
||||||
|
class sistemas_por_cliente(models.Model):
|
||||||
|
id_sistema= models.ForeignKey(Sistema, related_name='sistema_spc', on_delete=models.CASCADE)
|
||||||
|
cliente = models.ForeignKey(Clientes, related_name='cliente_spc', on_delete=models.CASCADE)
|
||||||
|
num_licencias= models.IntegerField(default=1)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
|
||||||
|
return f'{self.cliente.Nombre}'
|
||||||
|
class Meta:
|
||||||
|
ordering= ('-cliente','id_sistema')
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceManager(BaseUserManager):
|
||||||
|
def generate_unique_username(self,client, device_name, ip_address):
|
||||||
|
username = f"Device_{client.RFC}_{device_name}_{ip_address}"
|
||||||
|
username_ = re.sub(r'\W+', '', username)
|
||||||
|
if User.objects.filter(username=username_).exists():
|
||||||
|
raise ValidationError(f"El Usuario ya existe {username_}")
|
||||||
|
return username_
|
||||||
|
|
||||||
|
def create_user(self,client, device_name, device_os, ip_address ):
|
||||||
|
user_= User.objects.create_user(
|
||||||
|
username=self.generate_unique_username(client,device_name,ip_address)
|
||||||
|
)
|
||||||
|
device =self.model(
|
||||||
|
client=client,
|
||||||
|
device_name= device_name,
|
||||||
|
device_os=device_os,
|
||||||
|
ip_address=ip_address,
|
||||||
|
username=user_
|
||||||
|
)
|
||||||
|
device.save()
|
||||||
|
|
||||||
|
Token.objects.create(user=user_)
|
||||||
|
DeviceHistory.objects.create(device=device)
|
||||||
|
return device
|
||||||
|
|
||||||
|
class Device(models.Model):
|
||||||
|
client = models.ForeignKey(Clientes,on_delete=models.CASCADE)
|
||||||
|
device_name = models.CharField(max_length=255)
|
||||||
|
device_os = models.CharField(max_length=255)
|
||||||
|
ip_address= models.GenericIPAddressField()
|
||||||
|
token = models.OneToOneField(Token, on_delete=models.CASCADE, blank=True,null=True)
|
||||||
|
username = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||||
|
sistema = models.ForeignKey(Sistema,on_delete=models.CASCADE, blank=True, null=True)
|
||||||
|
macAddress = models.CharField(max_length=30, unique=True, blank=True,null=True)
|
||||||
|
#objects = DeviceManager()
|
||||||
|
def generate_unique_username(self,client, device_name,ip_address, macAddress):
|
||||||
|
username = f"Device_{client.RFC}_{device_name}_{ip_address}_{macAddress}"
|
||||||
|
username_ = re.sub(r'\W+', '', username)
|
||||||
|
|
||||||
|
if User.objects.filter(username=username_).exists():
|
||||||
|
raise ValidationError(f"El Usuario ya existe {username_}")
|
||||||
|
obj= User.objects.create_user(
|
||||||
|
username=username_
|
||||||
|
)
|
||||||
|
return obj
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.pk:
|
||||||
|
obj = self.generate_unique_username(self.client,self.device_name, self.ip_address, self.macAddress)
|
||||||
|
self.username= obj
|
||||||
|
token= Token.objects.create(user=obj)
|
||||||
|
self.token=token
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
DeviceHistory.objects.create(device=self,ip_address=self.ip_address)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.username}'
|
||||||
|
|
||||||
|
class DeviceHistory(models.Model):
|
||||||
|
device = models.ForeignKey(Device, on_delete=models.CASCADE)
|
||||||
|
first_authentication = models.DateTimeField(auto_now_add=True)
|
||||||
|
last_authentication = models.DateTimeField(auto_now=True)
|
||||||
|
ip_address = models.GenericIPAddressField()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Maquinas_Conectadas(models.Model):
|
||||||
|
|
||||||
|
UserName = models.CharField(max_length=255)
|
||||||
|
PC_Name = models.CharField(max_length=255)
|
||||||
|
Is64 = models.BooleanField()
|
||||||
|
OSversion= models.CharField(max_length=255)
|
||||||
|
local_ip = models.CharField(max_length=55)
|
||||||
|
public_ip= models.CharField(max_length=55)
|
||||||
|
|
||||||
|
Token = models.CharField(max_length=50)
|
||||||
|
Cliente = models.CharField(max_length=13)
|
||||||
|
class Meta:
|
||||||
|
abstract =True
|
||||||
14
Sistemas/permissions.py
Normal file
14
Sistemas/permissions.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from rest_framework.permissions import BasePermission
|
||||||
|
|
||||||
|
|
||||||
|
class HasAuthorizationHeader(BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return 'Authorization' in request.headers
|
||||||
|
|
||||||
|
class ItsAdminToken(BasePermission):
|
||||||
|
def has_permission(self,request,view):
|
||||||
|
return request.user.is_superuser
|
||||||
|
|
||||||
|
class ItsAdminGroup(BasePermission):
|
||||||
|
def has_permission(self, request, view):
|
||||||
|
return request.user.groups.filter(name= 'admin_soft')
|
||||||
49
Sistemas/serializers.py
Normal file
49
Sistemas/serializers.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
from rest_framework import serializers
|
||||||
|
from .models import Device, Sistema, sistemas_por_cliente
|
||||||
|
from Clientes.models import Clientes
|
||||||
|
|
||||||
|
class SistemaPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
def to_internal_value(self,data):
|
||||||
|
try:
|
||||||
|
return Sistema.objects.get(nombre_sistema=data)
|
||||||
|
except Sistema.DoesNotExist:
|
||||||
|
raise serializers.ValidationError("Sistema no existe")
|
||||||
|
|
||||||
|
class ClientPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
|
||||||
|
def to_internal_value(self,data):
|
||||||
|
try:
|
||||||
|
return Clientes.objects.get(RFC=data)
|
||||||
|
except Clientes.DoesNotExist:
|
||||||
|
raise serializers.ValidationError("No existe Cliente")
|
||||||
|
|
||||||
|
class DeviceSerializer(serializers.ModelSerializer):
|
||||||
|
client = ClientPrimaryKeyRelatedField(queryset=Clientes.objects.all())
|
||||||
|
sistema = SistemaPrimaryKeyRelatedField(queryset=Sistema.objects.all())
|
||||||
|
|
||||||
|
#this read_only fields not are required to be updated in the serializer.
|
||||||
|
#however in the model are required in other instantiation like queries, forms, are required to add it
|
||||||
|
token = serializers.CharField(read_only=True)
|
||||||
|
macAddress = serializers.CharField(read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model =Device
|
||||||
|
fields = ('client','sistema','device_name','device_os', 'ip_address','token', 'macAddress')
|
||||||
|
|
||||||
|
#this assign the masAddress value from
|
||||||
|
#the request context passed throught argument in the view to the serializer
|
||||||
|
#given that the macAddres field are read_Only in the beggining of this serialazer
|
||||||
|
#we need passing the post data to the creation instance before commited to the DB
|
||||||
|
def create(self, validated_data):
|
||||||
|
validated_data['macAddress']= self.context['request'].data.get('macAddress')
|
||||||
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
sistema = data.get('sistema', None)
|
||||||
|
client = data.get('client', None)
|
||||||
|
try:
|
||||||
|
sistemaxCli = sistemas_por_cliente.objects.get(id_sistema=sistema,cliente=client)
|
||||||
|
except sistemas_por_cliente.DoesNotExist:
|
||||||
|
raise serializers.ValidationError('No existe licencia para este sistmea y/o cliente')
|
||||||
|
if sistemaxCli.num_licencias <= Device.objects.filter(sistema=sistemaxCli.id_sistema).count():
|
||||||
|
raise serializers.ValidationError(f"No hay licencias disponibles para este sistema:{sistema} y cliente:{client}")
|
||||||
|
return data
|
||||||
3
Sistemas/tests.py
Normal file
3
Sistemas/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
22
Sistemas/urls.py
Normal file
22
Sistemas/urls.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from django.urls import path
|
||||||
|
|
||||||
|
from .views import (
|
||||||
|
|
||||||
|
#CVB
|
||||||
|
SistemasXCliente_ListView,
|
||||||
|
SistemasXCliente_DetailView,
|
||||||
|
UsersConnectedList,
|
||||||
|
|
||||||
|
#DRF APIViews
|
||||||
|
RegisterDeviceView,
|
||||||
|
AuthenticateDeviceView,
|
||||||
|
LogoutView,
|
||||||
|
)
|
||||||
|
urlpatterns = [
|
||||||
|
path('',SistemasXCliente_ListView.as_view(),name='lista_sistmas'),
|
||||||
|
path('detail/<str:pk>/',SistemasXCliente_DetailView.as_view(),name='detail_sistemas'),
|
||||||
|
path('registerPC/',RegisterDeviceView.as_view(),name='register_PC'),
|
||||||
|
path('authenticatePC/',AuthenticateDeviceView.as_view(), name="authenticateDevice"),
|
||||||
|
path('logout/', LogoutView.as_view(), name='logout_sistemas'),
|
||||||
|
path('usuariosConectados/', UsersConnectedList.as_view(), name='lista_usuarios'),
|
||||||
|
]
|
||||||
130
Sistemas/views.py
Normal file
130
Sistemas/views.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from django.contrib.auth import logout
|
||||||
|
from django.views.generic.list import ListView
|
||||||
|
from django.views.generic.detail import DetailView
|
||||||
|
from rest_framework.authentication import TokenAuthentication
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework.permissions import IsAuthenticated
|
||||||
|
from rest_framework import status, permissions
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
|
||||||
|
from .models import sistemas_por_cliente, DeviceHistory,Device
|
||||||
|
from .serializers import DeviceSerializer
|
||||||
|
from .permissions import HasAuthorizationHeader
|
||||||
|
from django.utils import timezone
|
||||||
|
import re
|
||||||
|
|
||||||
|
from rest_framework.authtoken.models import Token
|
||||||
|
from django.utils import timezone
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.contrib.sessions.models import Session
|
||||||
|
|
||||||
|
def get_logged_in_users():
|
||||||
|
sessions = Session.objects.filter(expire_date__gte=timezone.now())
|
||||||
|
|
||||||
|
# Get all non-expired tokens
|
||||||
|
#tokens = Token.objects.filter(created__gte=timezone.now() - timedelta(hours=1))
|
||||||
|
tokens = Token.objects.all()
|
||||||
|
|
||||||
|
# Get a list of logged-in user ids
|
||||||
|
uid_list = [token.user_id for token in tokens]
|
||||||
|
|
||||||
|
# Get the logged-in users
|
||||||
|
users = User.objects.filter(id__in=uid_list)
|
||||||
|
for user,session in zip(users,sessions):
|
||||||
|
user.session_data = session.get_decoded()
|
||||||
|
user.session_expire = session.expire_date
|
||||||
|
return users
|
||||||
|
|
||||||
|
class UsersConnectedList(UserPassesTestMixin,LoginRequiredMixin,ListView):
|
||||||
|
model = User
|
||||||
|
template_name= 'Sistemas/Usuarios/lista.html'
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return get_logged_in_users()
|
||||||
|
|
||||||
|
def test_func(self):
|
||||||
|
res = self.request.user.groups.filter(name= 'admin_soft')
|
||||||
|
if not res:
|
||||||
|
messages.error(self.request, f'Lo sentimos. La página que buscas no está disponible, no cuentas con los permisos.')
|
||||||
|
return res
|
||||||
|
|
||||||
|
class SistemasXCliente_ListView(UserPassesTestMixin,LoginRequiredMixin, ListView):
|
||||||
|
model = sistemas_por_cliente
|
||||||
|
paginate_by = 5
|
||||||
|
template_name = 'Sistemas/Xclientes/lista.html'
|
||||||
|
def test_func(self):
|
||||||
|
res = self.request.user.groups.filter(name= 'admin_soft')
|
||||||
|
if not res:
|
||||||
|
messages.error(self.request, f'Lo sentimos. La página que buscas no está disponible, no cuentas con los permisos.')
|
||||||
|
return res
|
||||||
|
|
||||||
|
class SistemasXCliente_DetailView(UserPassesTestMixin,LoginRequiredMixin, DetailView):
|
||||||
|
model = sistemas_por_cliente
|
||||||
|
template_name= 'Sistemas/Xclientes/detail.html'
|
||||||
|
def test_func(self):
|
||||||
|
res = self.request.user.groups.filter(name= 'admin_soft')
|
||||||
|
if not res:
|
||||||
|
messages.error(self.request, f'Lo sentimos. La página que buscas no está disponible, no cuentas con los permisos.')
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
========================= API Views
|
||||||
|
'''
|
||||||
|
|
||||||
|
class RegisterDeviceView(APIView):
|
||||||
|
permissions_classes = (permissions.AllowAny,)
|
||||||
|
|
||||||
|
def post(self,request):
|
||||||
|
try:
|
||||||
|
serializer = DeviceSerializer(data=request.data,context={'request':request})
|
||||||
|
if serializer.is_valid():
|
||||||
|
serializer.save()
|
||||||
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||||
|
else:
|
||||||
|
return Response({'Error':f'{serializer.errors}','isError':True}, status=status.HTTP_200_OK)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{'Error':f'{e}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticateDeviceView(APIView):
|
||||||
|
authentication_classes= [TokenAuthentication]
|
||||||
|
permissions_classes=[IsAuthenticated, HasAuthorizationHeader]
|
||||||
|
|
||||||
|
def get(self, request):
|
||||||
|
try:
|
||||||
|
obj, created = DeviceHistory.objects.get_or_create(
|
||||||
|
device=request.user.device,
|
||||||
|
ip_address=request.META.get('REMOTE_ADDR'),
|
||||||
|
)
|
||||||
|
obj.last_authentication=timezone.now()
|
||||||
|
obj.save()
|
||||||
|
device_data=DeviceSerializer(request.user.device).data
|
||||||
|
if device_data.serializer.is_valid:
|
||||||
|
return Response(device_data.serializer.data, status=status.HTTP_200_OK)
|
||||||
|
else:
|
||||||
|
return Response(
|
||||||
|
{'Error':f'{device_data.serializer.errors}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK)
|
||||||
|
except Exception as e:
|
||||||
|
return Response(
|
||||||
|
{'Error':f'{e}','isError':True}
|
||||||
|
, status=status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class LogoutView(APIView):
|
||||||
|
authentication_classes = (TokenAuthentication,)
|
||||||
|
permission_classes = (IsAuthenticated,HasAuthorizationHeader,)
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
logout(request)
|
||||||
|
return Response({'OK':'Dispositivo desautenticado'},status=200)
|
||||||
35
Templates/404.html
Normal file
35
Templates/404.html
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Required meta tags -->
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
|
||||||
|
<!-- Bootstrap CSS -->
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
|
||||||
|
|
||||||
|
<title>AS Admin Pagina No Encontrada</title>
|
||||||
|
</head>
|
||||||
|
<body >
|
||||||
|
<div>
|
||||||
|
{% include 'partials/messages.html' %}
|
||||||
|
<img class="rounded mx-auto d-block" src="https://static.doofinder.com/main-files/uploads/2019/08/110655-404-not-found-Doofinder.jpg" alt="Forbidden">
|
||||||
|
<a href="/" class="btn btn-info btn-lg rounded mx-auto d-block mt-3">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-arrow-return-left" viewBox="0 0 16 16">
|
||||||
|
<path fill-rule="evenodd" d="M14.5 1.5a.5.5 0 0 1 .5.5v4.8a2.5 2.5 0 0 1-2.5 2.5H2.707l3.347 3.346a.5.5 0 0 1-.708.708l-4.2-4.2a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 8.3H12.5A1.5 1.5 0 0 0 14 6.8V2a.5.5 0 0 1 .5-.5z"/>
|
||||||
|
</svg>
|
||||||
|
Regresar al Inicio
|
||||||
|
</a>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Optional JavaScript -->
|
||||||
|
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||||
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
69
Templates/Clientes/Errores_Timbres_list.html
Normal file
69
Templates/Clientes/Errores_Timbres_list.html
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="table-responsive-sm">
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">UUID</th>
|
||||||
|
<th scope="col">Error</th>
|
||||||
|
<th scope="col">RCF</th>
|
||||||
|
<th scope="col">Folio</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for errTimbre in object_list %}
|
||||||
|
<tr class="{% if errTimbre.modo|lower == 'prueba' %}table-danger{% endif %}">
|
||||||
|
<th scope="row">{{errTimbre.uuid}}</th>
|
||||||
|
<td>{{errTimbre.description}}</td>
|
||||||
|
<td>{{errTimbre.rfcc}}</td>
|
||||||
|
<td>{{errTimbre.folio}}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if page_obj.has_other_pages %}
|
||||||
|
|
||||||
|
<nav>
|
||||||
|
<ul class="pagination justify-content-center">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}" aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link" aria-hidden="true">«</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for p in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == p %}
|
||||||
|
<li class="page-item"><a class="page-link" style="color: red;" href="#">{{ p }}</a></li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item"><a class="page-link" href="?page={{ p }}{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}">{{ p }}</a></li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% else %}
|
||||||
|
<li class="page-item disabled">
|
||||||
|
<span class="page-link" aria-hidden="true">»</span>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
@@ -19,10 +19,32 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
<th>Nombre</th>
|
<th>Nombre</th>
|
||||||
<th>
|
<th>
|
||||||
<div class="d-flex align-items-center">
|
<div class="d-flex align-items-center">
|
||||||
Totales Mes
|
<div class="">
|
||||||
<div style="display:none" id="spinner_id" class="spinner-border ml-auto spinner-border-sm" role="status" aria-hidden="true"></div>
|
<a data-toggle="collapse" href="#collapseExample" role="button" aria-expanded="false" aria-controls="collapseExample">
|
||||||
</div>
|
Total x mes
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<small>
|
||||||
|
<strong>
|
||||||
|
Filtrado: Mes:{{mes}}, Año:{{year}}, PAC:<label id="lbl_pac"></label>
|
||||||
|
</strong>
|
||||||
|
</small>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="display:none;" id="spinner_id" class="spinner-border ml-auto spinner-border-sm" role="status" aria-hidden="true"></div>
|
||||||
|
</div>
|
||||||
|
<div class="collapse" id="collapseExample">
|
||||||
|
<div class="card card-body">
|
||||||
|
<!--PACS-->
|
||||||
|
<select id="table_select_PAC" class="form-control form-control-sm my_event_cls">
|
||||||
|
<option value="00">Todos</option>
|
||||||
|
<!--option value="01">EDICOM</option-->
|
||||||
|
</select>
|
||||||
|
<!--ANIOS-->
|
||||||
|
<select style="display:inline" id="table_select_anio" class="form-control form-control-sm">
|
||||||
|
<!--option value="0"></option-->
|
||||||
|
</select>
|
||||||
|
<!--MESES-->
|
||||||
<select id="table_select" class="form-control form-control-sm">
|
<select id="table_select" class="form-control form-control-sm">
|
||||||
<option value="01">Enero</option>
|
<option value="01">Enero</option>
|
||||||
<option value="02">Febrero</option>
|
<option value="02">Febrero</option>
|
||||||
@@ -47,7 +69,8 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
<option value="12">Diciembre
|
<option value="12">Diciembre
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</th>
|
</th>
|
||||||
<th>Estado</th>
|
<th>Estado</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
@@ -119,7 +142,7 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
|
||||||
<!-- Button trigger modal -->
|
<!-- Button trigger modal -->
|
||||||
<button class="btn btn-primary w-100" onclick="addValues('{{obj.RFC}}')" type="button" data-toggle="modal" data-target="#exampleModalCenter">
|
<button class="btn btn-primary w-100" onclick="addValues('{{obj.RFC}}'); retriveEmails('{{obj.RFC}}');" type="button" data-toggle="modal" data-target="#exampleModalCenter">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope-plus" viewBox="0 0 16 16">
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-envelope-plus" viewBox="0 0 16 16">
|
||||||
<path d="M2 2a2 2 0 0 0-2 2v8.01A2 2 0 0 0 2 14h5.5a.5.5 0 0 0 0-1H2a1 1 0 0 1-.966-.741l5.64-3.471L8 9.583l7-4.2V8.5a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2H2Zm3.708 6.208L1 11.105V5.383l4.708 2.825ZM1 4.217V4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v.217l-7 4.2-7-4.2Z"/>
|
<path d="M2 2a2 2 0 0 0-2 2v8.01A2 2 0 0 0 2 14h5.5a.5.5 0 0 0 0-1H2a1 1 0 0 1-.966-.741l5.64-3.471L8 9.583l7-4.2V8.5a.5.5 0 0 0 1 0V4a2 2 0 0 0-2-2H2Zm3.708 6.208L1 11.105V5.383l4.708 2.825ZM1 4.217V4a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v.217l-7 4.2-7-4.2Z"/>
|
||||||
<path d="M16 12.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Zm-3.5-2a.5.5 0 0 0-.5.5v1h-1a.5.5 0 0 0 0 1h1v1a.5.5 0 0 0 1 0v-1h1a.5.5 0 0 0 0-1h-1v-1a.5.5 0 0 0-.5-.5Z"/>
|
<path d="M16 12.5a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Zm-3.5-2a.5.5 0 0 0-.5.5v1h-1a.5.5 0 0 0 0 1h1v1a.5.5 0 0 0 1 0v-1h1a.5.5 0 0 0 0-1h-1v-1a.5.5 0 0 0-.5-.5Z"/>
|
||||||
@@ -136,11 +159,11 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div id='id_filters' style="display: none;">{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}</div>
|
|
||||||
|
|
||||||
<!-- Modal -->
|
<div id='id_filters' style="display: none;">{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}</div>
|
||||||
|
<!-- Modal EMAIL-->
|
||||||
<div class="modal fade" data-backdrop="static" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
<div class="modal fade" data-backdrop="static" id="exampleModalCenter" tabindex="-1" role="dialog" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
||||||
<form enctype="multipart/form-data" id="id_form" action="{% url 'send_timbres_Email' %}" method="post">
|
<form enctype="multipart/form-data" id="id_form" action="{% url 'send_timbres_Email' %}?mes={{mes}}{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}" method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
@@ -153,8 +176,18 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="email"><strong>Email</strong></label>
|
<label for="email"><strong>Email</strong></label>
|
||||||
<input type="email" name="email" id="email_add" autocomplete="off" class="form-control" placeholder="Email">
|
<!--input type="email" name="email" id="email_add" autocomplete="off" class="form-control" placeholder="Email"-->
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="email" name="email" id="email_add" class="form-control" placeholder="Email" aria-label="Email" aria-describedby="button-addon2">
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button class="btn btn-outline-secondary" type="button" data-toggle="modal" data-target="#exampleModalCenter2" id="button-addon2" >
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-search" viewBox="0 0 16 16">
|
||||||
|
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="subject"><strong> Subject </strong></label>
|
<label for="subject"><strong> Subject </strong></label>
|
||||||
@@ -167,7 +200,7 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="message"><strong>Message</strong></label>
|
<label for="message"><strong>Message</strong></label>
|
||||||
<textarea name="message" cols="40" rows="10" id="message_add" autocomplete="off" class="form-control" placeholder="Message" ></textarea>
|
<textarea name="message" cols="40" rows="10" id="message_add" autocomplete="off" class="form-control" placeholder="Message" required></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div hidden class="form-group">
|
<div hidden class="form-group">
|
||||||
<label for="RFC"><strong> Rfc </strong></label>
|
<label for="RFC"><strong> Rfc </strong></label>
|
||||||
@@ -190,12 +223,133 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Modal LISTA EMAILS-->
|
||||||
|
<div class="modal fade bd-example-modal-lg" id="exampleModalCenter2" tabindex="-1" role="contentinfo" aria-labelledby="exampleModalCenterTitle" aria-hidden="true">
|
||||||
|
<div class="modal-dialog modal-lg" role="document">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h5 class="modal-title" id="exampleModalCenterTitle">Lista email</h5>
|
||||||
|
<button id="close_emails_list" type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table id="email_list" class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">EMAIL</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="table_body" style="cursor: pointer;">
|
||||||
|
<!--This is a exaple append js rows structure---->
|
||||||
|
<!--tr class="table_row"><td id="1">@Mark</td></tr-->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<h1>Footer</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
function retriveEmails(RFC){
|
||||||
|
fetch(`{% url 'Retrive_Cliente_Email' %}?RFC=${RFC}`,{
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'X-Requested-With':'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
credentials:"same-origin"
|
||||||
|
})
|
||||||
|
.then(res=>{
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then(data=>{
|
||||||
|
|
||||||
|
if(table_body.querySelectorAll('tr').length >0){
|
||||||
|
const table_rows = document.querySelectorAll('.table_row')
|
||||||
|
table_rows.forEach((rem)=>{
|
||||||
|
rem.remove()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const re = Object.values(data['data'])
|
||||||
|
re.forEach((val,index)=>{
|
||||||
|
|
||||||
|
const row = document.createElement("tr")
|
||||||
|
row.setAttribute("class","table_row")
|
||||||
|
const cell = document.createElement("td")
|
||||||
|
cell.setAttribute("id",index)
|
||||||
|
const cellText = document.createTextNode(`${val.email}`)
|
||||||
|
cell.appendChild(cellText)
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
table_body.appendChild(row)
|
||||||
|
})
|
||||||
|
|
||||||
|
email_list.appendChild(table_body)
|
||||||
|
const table_rows = document.querySelectorAll('.table_row')
|
||||||
|
table_rows.forEach((box)=>{
|
||||||
|
box.addEventListener('click',(event)=>{
|
||||||
|
email_add.value=event.target.textContent
|
||||||
|
close_emails_list.click()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})//.then(data)
|
||||||
|
}
|
||||||
|
|
||||||
let filters = document.getElementById('id_filters').textContent
|
let filters = document.getElementById('id_filters').textContent
|
||||||
console.log(filters)
|
let mes ='{{mes}}'
|
||||||
|
let year = parseInt('{{year}}')
|
||||||
|
let anc = document.getElementById('home_id')
|
||||||
|
let PAC = Object.values(filters.split('&'))
|
||||||
|
PAC.filter(val=>{
|
||||||
|
lbl_pac.innerHTML="Todos"
|
||||||
|
if(val.length >0){
|
||||||
|
lbl_pac.innerHTML= val.split('=')[1]=="" ? "Todos" :val.split('=')[1]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-------------------------Carga los pacs*/
|
||||||
|
fetch("{% url 'PACS_Retrive_RFCS' %}",{
|
||||||
|
method:'GET',
|
||||||
|
headers:{
|
||||||
|
'Content-Type':'application/json',
|
||||||
|
'X-Requested-With':'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
credentials:"same-origin"
|
||||||
|
})
|
||||||
|
.then(res=>{
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then(data=>{
|
||||||
|
let pacs = [...new Set(data['PACS'].map((arr)=>arr.rfcp) )]
|
||||||
|
|
||||||
|
pacs.forEach((val,index)=>{
|
||||||
|
let option = document.createElement('option')
|
||||||
|
option.value=val
|
||||||
|
option.text=val
|
||||||
|
table_select_PAC.add(option)
|
||||||
|
PAC.filter(val=>val.includes('PAC'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
table_select_PAC.value = val.split('=')[1]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(error=>{
|
||||||
|
console.log(error)
|
||||||
|
})
|
||||||
|
/*----------------------fin carga pacs*/
|
||||||
|
|
||||||
function aclick(event,RFC ,cuantos){
|
function aclick(event,RFC ,cuantos){
|
||||||
|
|
||||||
if( parseInt(cuantos)===0){
|
if( parseInt(cuantos)===0){
|
||||||
@@ -211,24 +365,72 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
})
|
})
|
||||||
|
|
||||||
window.addEventListener("load", (event)=>{
|
window.addEventListener("load", (event)=>{
|
||||||
let mes ='{{mes}}'
|
// let mes ='{{mes}}'
|
||||||
|
|
||||||
|
mes.length == 1 ? mes="0"+mes: mes
|
||||||
if(mes !="None"){
|
if(mes !="None"){
|
||||||
document.getElementById('table_select').value='{{mes}}'
|
document.getElementById('table_select').value=mes
|
||||||
mes_id.value='{{mes}}'
|
mes_id.value=mes
|
||||||
}else{
|
}else{
|
||||||
document.getElementById('table_select').value='{{fecha|date:"m"}}'
|
document.getElementById('table_select').value='{{fecha|date:"m"}}'
|
||||||
mes_id.value='{{fecha|date:"m"}}'
|
mes_id.value='{{fecha|date:"m"}}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*Add years to select anio tag*/
|
||||||
|
|
||||||
|
let anio = parseInt('{{fecha|date:"Y"}}')
|
||||||
|
|
||||||
|
let fin = anio-5
|
||||||
|
for(var i = anio; i >= fin ;i--){
|
||||||
|
let option = document.createElement('option')
|
||||||
|
option.value=i
|
||||||
|
option.text=i
|
||||||
|
table_select_anio.add(option)
|
||||||
|
}
|
||||||
|
/*despues de agregar los anios al control agrega el value del contexto*/
|
||||||
|
table_select_anio.value=year
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
document.getElementById('table_select').addEventListener('change',(event)=>{
|
document.getElementById('table_select').addEventListener('change',(event)=>{
|
||||||
spinner_id.setAttribute('style','display:inline;')
|
spinner_id.setAttribute('style','display:inline;')
|
||||||
let anc = document.getElementById('home_id')
|
|
||||||
|
|
||||||
anc.href=''
|
anc.href=''
|
||||||
let url = `?mes=${event.target.value}${filters}`
|
|
||||||
|
let url = `?mes=${event.target.value}&year=${year}${filters}`
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
anc.href=url
|
anc.href=url
|
||||||
anc.click()
|
anc.click()
|
||||||
|
},1000)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
table_select_anio.addEventListener('change',(event)=>{
|
||||||
|
spinner_id.setAttribute('style','display:inline;')
|
||||||
|
|
||||||
|
|
||||||
|
anc.href=''
|
||||||
|
|
||||||
|
let url = `?mes=${mes}&year=${event.target.value}${filters}`
|
||||||
|
|
||||||
|
setTimeout(()=>{
|
||||||
|
anc.href=url
|
||||||
|
anc.click()
|
||||||
|
},1000)
|
||||||
|
})
|
||||||
|
|
||||||
|
table_select_PAC.addEventListener('change',(event)=>{
|
||||||
|
spinner_id.setAttribute('style','display:inline;');
|
||||||
|
anc.href='';
|
||||||
|
let url =`?mes=${mes}&year=${year}&PAC=${event.target.value}`
|
||||||
|
setTimeout(()=>{
|
||||||
|
anc.href=url
|
||||||
|
anc.click()
|
||||||
|
},1000)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
enviar_btn.addEventListener('click',(e)=>{
|
enviar_btn.addEventListener('click',(e)=>{
|
||||||
@@ -236,12 +438,7 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
if(id_form.checkValidity()){
|
if(id_form.checkValidity()){
|
||||||
//
|
//
|
||||||
spinner_enviar.removeAttribute('style');
|
spinner_enviar.removeAttribute('style');
|
||||||
/*
|
|
||||||
id_form.getElementsByTagName('*');
|
|
||||||
for (var node of childNodes) {
|
|
||||||
node.disabled = true;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -253,7 +450,7 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
fsize = id_adjunto.files.item(i).size
|
fsize = id_adjunto.files.item(i).size
|
||||||
|
|
||||||
fsize +=fsize;
|
fsize +=fsize;
|
||||||
console.log(((fsize/1024)/1024))
|
|
||||||
if( 25 <= ((fsize/1024)/1024) ){
|
if( 25 <= ((fsize/1024)/1024) ){
|
||||||
alert('Limite excedido de 25 MegaBytes adjuntos');
|
alert('Limite excedido de 25 MegaBytes adjuntos');
|
||||||
id_adjunto.value=''
|
id_adjunto.value=''
|
||||||
@@ -270,10 +467,10 @@ Timbres disponibles Comercio Digital: {{saldo}}
|
|||||||
})
|
})
|
||||||
|
|
||||||
function addValues(RFC){
|
function addValues(RFC){
|
||||||
|
|
||||||
RFC_add.value = RFC
|
RFC_add.value = RFC
|
||||||
console.log('RFC', RFC)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
|
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Timbres <strong>{{RFC}}</strong> </h1>
|
<h1>Timbres <strong>{{RFC}}</strong> </h1>
|
||||||
<h2>Timbres totales: <strong></strong>{{conteo}}</strong></h2>
|
<h2>Timbres totales: <strong></strong>{{conteo}}</strong></h2>
|
||||||
<span class="navbar-text mr-2">
|
|
||||||
|
<span class="justify-content-sm-end navbar-text mr-2">
|
||||||
{% if filters.datepicker%}
|
{% if filters.datepicker%}
|
||||||
De fecha: <strong>"{{filters.datepicker}}"</strong>
|
De fecha: <strong>"{{filters.datepicker}}"</strong>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -22,23 +20,40 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th scope="col"> UUID</th>
|
<th scope="col"> UUID</th>
|
||||||
|
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
PAC
|
PAC
|
||||||
<select id="table_select_PAC" class="form-control form-control-sm">
|
<select id="table_select_PAC" class="form-control form-control-sm my_event_cls">
|
||||||
<option value="00">Todos</option>
|
<option value="00">Todos</option>
|
||||||
<option value="01">EDICOM</option>
|
<!--option value="01">EDICOM</option-->
|
||||||
<option value="02">Comercio Dig.</option>
|
|
||||||
</select>
|
</select>
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
<input id="table_tipo" name="tipo" value="True" type="checkbox" class="form-check-input" >
|
<input id="table_tipo" name="tipo" value="True" type="checkbox" class="form-check-input my_event_cls" >
|
||||||
Tipo CFDI
|
Tipo CFDI
|
||||||
</th>
|
</th>
|
||||||
<th scope="col">Serie/Folio</th>
|
<th scope="col">Serie/Folio</th>
|
||||||
<th scope="col">
|
<th scope="col">
|
||||||
<input id="table_fecha" name="fecha" value="True" type="checkbox" class="form-check-input" >
|
<input id="table_fecha" name="fecha" value="True" type="checkbox" class="form-check-input my_event_cls" >
|
||||||
Fecha
|
Fecha
|
||||||
|
<select id="table_select_anio" class="form-control form-control-sm my_event_cls">
|
||||||
|
<!--option value="2023"></option-->
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="table_select_Meses" class="form-control form-control-sm my_event_cls">
|
||||||
|
<option value="00">Todos</option>
|
||||||
|
<option value="01">Enero</option>
|
||||||
|
<option value="02">Febrero</option>
|
||||||
|
<option value="03">Marzo</option>
|
||||||
|
<option value="04">Abril</option>
|
||||||
|
<option value="05">Mayo</option>
|
||||||
|
<option value="06">Junio</option>
|
||||||
|
<option value="07">Julio</option>
|
||||||
|
<option value="08">Agosto</option>
|
||||||
|
<option value="09">Septiembre</option>
|
||||||
|
<option value="10">Octubre</option>
|
||||||
|
<option value="11">Noviembre</option>
|
||||||
|
<option value="12">Diciembre</option>
|
||||||
|
</select>
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -56,26 +71,151 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div id='id_filters' style="display: None;">{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}</div>
|
<div id='id_filters' style="display: none;">{% for i,v in filters.items %}&{{i}}={{v}}{% endfor%}</div>
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
||||||
|
|
||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
<script>
|
<script>
|
||||||
window.addEventListener("load", (event)=>{
|
function get_pacs(){
|
||||||
let PAC = '{{PAC}}'
|
|
||||||
if(PAC !="None"){
|
let rfc = '{{request.path}}'
|
||||||
table_select_PAC.value=PAC
|
rfc= Object.values(rfc.split('/'))
|
||||||
|
url = `{% url 'PACS_Retrive_RFCS' %}?RFC=${rfc[2]}`
|
||||||
|
fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers:{
|
||||||
|
'Content-Type':'application/json',
|
||||||
|
'X-Requested-With':'XMLHttpRequest',
|
||||||
|
},
|
||||||
|
credentials:"same-origin"
|
||||||
|
})
|
||||||
|
.then(res=>{
|
||||||
|
return res.json()
|
||||||
|
})
|
||||||
|
.then(data=>{
|
||||||
|
|
||||||
|
let pacs = [...new Set( data['PACS'].map((arr)=> arr.rfcp) )]
|
||||||
|
pacs.forEach((val,index)=>{
|
||||||
|
let option = document.createElement('option')
|
||||||
|
option.value=val
|
||||||
|
option.text=val
|
||||||
|
table_select_PAC.add(option)
|
||||||
|
PAC.filter(val=>val.includes('PAC'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
table_select_PAC.value = val.split('=')[1]
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<!--end functions-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let filters = document.getElementById('id_filters').textContent
|
||||||
|
let mes = Object.values(filters.split('&'))
|
||||||
|
let year = Object.values(filters.split('&'))
|
||||||
|
let PAC = Object.values(filters.split('&'))
|
||||||
|
let tipo = Object.values(filters.split('&'))
|
||||||
|
let lsearch = Object.values(filters.split('&'))
|
||||||
|
let ldatepicker = Object.values(filters.split('&'))
|
||||||
|
let ldatepickerFin = Object.values(filters.split('&'))
|
||||||
|
let anc = document.getElementById('home_id')
|
||||||
|
let ref=''
|
||||||
|
|
||||||
|
/*Add years to select anio tag*/
|
||||||
|
|
||||||
|
let anio = parseInt('{{fecha|date:"Y"}}')
|
||||||
|
|
||||||
|
let fin = anio-5
|
||||||
|
console.log(anio)
|
||||||
|
for(var i = anio; i >= fin ;i--){
|
||||||
|
let option = document.createElement('option')
|
||||||
|
option.value=i
|
||||||
|
option.text=i
|
||||||
|
table_select_anio.add(option)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
year.filter(val=> val.length>0)
|
||||||
|
.filter(val=>val.includes('year'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
table_select_anio.value=val.split('=')[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
mes.filter(val=> val.length >0)
|
||||||
|
.filter(val=>val.includes('mes'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
table_select_Meses.value= val.split('=')[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
tipo.filter(val=>val.includes('tipo'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
|
||||||
|
table_tipo.checked= val.split('=')[1] ==='on' ?true:false
|
||||||
|
})
|
||||||
|
|
||||||
|
lsearch.filter(val=>val.includes('search'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
search.value = val.split('=')[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
ldatepicker.filter(val=>val.includes('datepicker'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
datepicker.value=val.split('=')[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
ldatepickerFin.filter(val=>val.includes('datepicker'))
|
||||||
|
.forEach((val,index)=>{
|
||||||
|
datepickerFin.value=val.split('=')[1]
|
||||||
|
})
|
||||||
|
|
||||||
|
window.addEventListener('load',event=>{
|
||||||
|
get_pacs()
|
||||||
|
})
|
||||||
|
document.querySelectorAll('.my_event_cls').forEach(item=>{
|
||||||
|
if(item.id==='datepicker' || item.id==='datepickerFin'){
|
||||||
|
item.addEventListener('focusout',event=>{
|
||||||
|
ref=`?PAC=${table_select_PAC.value}`
|
||||||
|
ref+=`&mes=${table_select_Meses.value}`
|
||||||
|
ref+=`&year=${table_select_anio.value}`
|
||||||
|
ref+=`&tipo=${table_tipo.checked}`
|
||||||
|
ref+=`&search=${search.value}`
|
||||||
|
ref+=`&datepicker=${datepicker.value}`
|
||||||
|
ref+=`&datepickerFin=${datepickerFin.value}`
|
||||||
|
})
|
||||||
|
|
||||||
|
}else{
|
||||||
|
item.addEventListener('change', event=>{
|
||||||
|
ref=`?PAC=${table_select_PAC.value}`
|
||||||
|
ref+=`&mes=${table_select_Meses.value}`
|
||||||
|
ref+=`&year=${table_select_anio.value}`
|
||||||
|
ref+=`&tipo=${table_tipo.checked}`
|
||||||
|
ref+=`&search=${search.value}`
|
||||||
|
ref+=`&datepicker=${datepicker.value}`
|
||||||
|
ref+=`&datepickerFin=${datepickerFin.value}`
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
let filters = document.getElementById('id_filters').textContent
|
|
||||||
|
|
||||||
|
|
||||||
table_select_PAC.addEventListener('change',(event)=>{
|
table_select_PAC.addEventListener('change',(event)=>{
|
||||||
let anc = document.getElementById('home_id')
|
|
||||||
anc.href=''
|
anc.href=''
|
||||||
let url = `?PAC=${event.target.value}${filters}`
|
anc.href=ref
|
||||||
anc.href=url
|
anc.click()
|
||||||
|
})
|
||||||
|
table_select_Meses.addEventListener('change',(event)=>{
|
||||||
|
anc.href=''
|
||||||
|
anc.href=ref
|
||||||
|
anc.click()
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
table_select_anio.addEventListener('change',(event)=>{
|
||||||
|
anc.href=''
|
||||||
|
anc.href=ref
|
||||||
anc.click()
|
anc.click()
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -87,8 +227,6 @@
|
|||||||
})
|
})
|
||||||
|
|
||||||
table_fecha.addEventListener('click', (event)=>{
|
table_fecha.addEventListener('click', (event)=>{
|
||||||
|
|
||||||
|
|
||||||
if(dates.hasAttribute("style")){
|
if(dates.hasAttribute("style")){
|
||||||
dates.removeAttribute('style')
|
dates.removeAttribute('style')
|
||||||
datepicker.value=''
|
datepicker.value=''
|
||||||
|
|||||||
33
Templates/Sistemas/Usuarios/lista.html
Normal file
33
Templates/Sistemas/Usuarios/lista.html
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
| Sistemas
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<table class="table">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">Usuario</th>
|
||||||
|
<th scope="col">Expira</th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th scope="col"></th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for user in object_list %}
|
||||||
|
<tr>
|
||||||
|
<th scope="row">{{user.username}}</th>
|
||||||
|
<td>Session expire at: {{ user.session_expire }}</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td><a href="#" class="btn btn-info">Detalles</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
89
Templates/Sistemas/Xclientes/detail.html
Normal file
89
Templates/Sistemas/Xclientes/detail.html
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{{object}} | Sistemas
|
||||||
|
{% endblock title %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Assistant');
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #eee;
|
||||||
|
font-family: Assistant, sans-serif
|
||||||
|
}
|
||||||
|
|
||||||
|
.cell-1 {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0 4em;
|
||||||
|
background: #ffffff;
|
||||||
|
border-bottom: 5px solid transparent;
|
||||||
|
/*background-color: gold;*/
|
||||||
|
background-clip: padding-box;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: #dddcdc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.table-elipse {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#demo {
|
||||||
|
-webkit-transition: all 0.3s ease-in-out;
|
||||||
|
-moz-transition: all 0.3s ease-in-out;
|
||||||
|
-o-transition: all 0.3s 0.1s ease-in-out;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row-child {
|
||||||
|
background-color: rgb(113, 178, 238);
|
||||||
|
color: rgb(0, 0, 0);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<h1>{{object.cliente}}</h1>
|
||||||
|
|
||||||
|
<div class="table-responsive table-borderless">
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="text-center">Num. Licencias contratadas</th>
|
||||||
|
<th>Sistema</th>
|
||||||
|
<th>-</th>
|
||||||
|
<th>Estatus</th>
|
||||||
|
<th>-</th>
|
||||||
|
<th>-</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="table-body">
|
||||||
|
<tr class="cell-1" data-toggle="collapse" data-target="#demo">
|
||||||
|
<td class="text-center">{{object.num_licencias}}</td>
|
||||||
|
<td>{{object.id_sistema}}</td>
|
||||||
|
<td>-</td>
|
||||||
|
<td><span class="badge badge-{% if object.cliente.Activo %}success{%else%}danger{% endif %}">{% if object.cliente.Activo %}Activo{%else%}Inactivo{% endif %}</span></td>
|
||||||
|
<td>-</td>
|
||||||
|
<td>click me</td>
|
||||||
|
<td class="table-elipse" data-toggle="collapse" data-target="#demo"><i class="fa fa-ellipsis-h text-black-50"></i></td>
|
||||||
|
</tr>
|
||||||
|
{% for sistema in object.id_sistema.device_set.all %}
|
||||||
|
<tr id="demo" class="collapse cell-1 row-child">
|
||||||
|
<td class="text-center" colspan="1"><i class="fa fa-angle-up"></i></td>
|
||||||
|
<td colspan="1">Dispositivo: <strong>{{sistema}}</strong> </td>
|
||||||
|
<td colspan="3"></td>
|
||||||
|
<td colspan="1">-</td>
|
||||||
|
<td colspan="2">-</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
36
Templates/Sistemas/Xclientes/lista.html
Normal file
36
Templates/Sistemas/Xclientes/lista.html
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
Sistemas Lista
|
||||||
|
{% 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></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="{% url 'detail_sistemas' row.id %}" class="btn btn-info">Detalles</a></td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
|
|
||||||
@@ -43,8 +43,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
|
<div class="row">
|
||||||
|
<p>No recuerdas tu contrasena? <a href="/accounts/password/reset/">Reset password</a></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<p>No recuerdas tu contrasena? <a href="/accounts/password/reset/">Reset password</a></p>
|
||||||
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<p>Don't have an account? <a href="{{ signup_url }}">Register Here</a></p>
|
<p>Don't have an account? <a href="{{ signup_url }}">Register Here</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -40,6 +40,7 @@
|
|||||||
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"></script>
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -37,4 +37,3 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
|
||||||
@@ -2,29 +2,22 @@
|
|||||||
<span class="navbar-text mr-2">
|
<span class="navbar-text mr-2">
|
||||||
Fecha: <strong>{{fecha|date:"d F Y"}}</strong>
|
Fecha: <strong>{{fecha|date:"d F Y"}}</strong>
|
||||||
</span>
|
</span>
|
||||||
<form action="{{request.path}}" method="get" class="form-inline my-2 my-lg-0">
|
<form id="searchForm" action="{{request.path}}" method="get" class="form-inline my-2 my-lg-0 my_event_cls">
|
||||||
<input style="display:none" id="mes_id" class="form-control mr-sm-2" name="mes" type="input" aria-label="mes">
|
|
||||||
<input id="search" class="form-control mr-sm-2" name="search" type="search" placeholder="Search" aria-label="Search">
|
<input style="display:none" id="mes_id" class="form-control mr-sm-2 my_event_cls" name="mes" type="input" aria-label="mes">
|
||||||
|
<input id="search" class="form-control mr-sm-2 my_event_cls" name="search" type="search" placeholder="Search" aria-label="Search">
|
||||||
|
|
||||||
<div class="form-group form-check">
|
<div class="form-group form-check">
|
||||||
<input style="display:none" name="rfcc" type="checkbox" class="form-check-input" id="rfcc">
|
<input style="display:none" name="rfcc" type="checkbox" class="form-check-input my_event_cls" id="rfcc">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group form-check">
|
<div class="form-group form-check">
|
||||||
<input style="display:none" name="tipo" type="checkbox" class="form-check-input" id="tipo">
|
<input style="display:none" name="tipo" type="checkbox" class="form-check-input my_event_cls" id="tipo">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="dates" style="display:none;" class="group-form mr-2" >
|
<div id="dates" style="display:none;" class="group-form mr-2" >
|
||||||
<input class="form-control sm-2" name ="datepicker" id="datepicker" placeholder="Initial Date" />
|
<input type="date" class="form-control sm-2 my_event_cls" name ="datepicker" id="datepicker" placeholder="Initial Date" />
|
||||||
<input class="form-control sm-2" name ="datepickerFin" id="datepickerFin" placeholder="End Date" />
|
<input type="date" class="form-control sm-2 my_event_cls" name ="datepickerFin" id="datepickerFin" placeholder="End Date" />
|
||||||
<script>
|
|
||||||
$('#datepicker').datepicker({
|
|
||||||
uiLibrary: 'bootstrap4'
|
|
||||||
});
|
|
||||||
$('#datepickerFin').datepicker({
|
|
||||||
uiLibrary: 'bootstrap4'
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
<button id="id_searchbtn" class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -39,8 +39,11 @@
|
|||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link disabled" href="#">Disabled</a>
|
<a class="nav-link disabled" href="#">Disabled</a>
|
||||||
</li>
|
</li>
|
||||||
{% endcomment %}
|
|
||||||
|
|
||||||
|
{% endcomment %}
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/sistemas" target="_blank">Sistemas</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>
|
||||||
@@ -61,14 +64,13 @@
|
|||||||
</form>
|
</form>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
|
||||||
<a class="dropdown-item" href="#">Another action</a>
|
{% if request.user.is_superuser %}
|
||||||
|
<a class="dropdown-item" href="{% url 'ErroresTimbresList' %}">Lista Errores</a>
|
||||||
<div class="dropdown-divider"></div>
|
<div class="dropdown-divider"></div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<a class="dropdown-item" href="#">Something else here</a>
|
<a class="dropdown-item" href="#">Something else here</a>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
Reference in New Issue
Block a user