diff --git a/Admin/settings.py b/Admin/settings.py index 57601c5..e04958b 100644 --- a/Admin/settings.py +++ b/Admin/settings.py @@ -9,21 +9,14 @@ import pytz # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent - - # Quick-start development settings - unsuitable for production # See https://docs.djangoproject.com/en/4.1/howto/deployment/checklist/ - # 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! DEBUG = False - ALLOWED_HOSTS = ['*'] - # Application definition - INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', @@ -31,7 +24,7 @@ INSTALLED_APPS = [ 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', - + 'rest_framework', 'rest_framework.authtoken', @@ -57,9 +50,7 @@ MIDDLEWARE = [ 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ] - ROOT_URLCONF = 'Admin.urls' - TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -118,15 +109,13 @@ EMAIL_USE_SSL=True # Database # https://docs.djangoproject.com/en/4.1/ref/settings/#databases - - if DEBUG: DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'cfdi_as', 'USER': 'root', - 'PASSWORD': 'Soluciones28@', + 'PASSWORD':os.getenv("BD_PASS"), 'HOST': '127.0.0.1', 'PORT': '', 'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"}, @@ -138,7 +127,7 @@ else: 'ENGINE': 'django.db.backends.mysql', 'NAME': 'fjrodriguez$cfdi_as', 'USER': 'fjrodriguez', - 'PASSWORD': 'Soluciones28@', + 'PASSWORD':os.getenv("BD_PASS"), 'HOST': 'fjrodriguez.mysql.pythonanywhere-services.com', 'PORT': '3306', 'OPTIONS': {'init_command': "SET sql_mode='STRICT_TRANS_TABLES'"}, diff --git a/Clientes/custom_decorators.py b/Clientes/custom_decorators.py index c635a1a..3387c19 100644 --- a/Clientes/custom_decorators.py +++ b/Clientes/custom_decorators.py @@ -1,9 +1,12 @@ from functools import wraps from django.contrib import messages 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): if user.is_staff: return True @@ -19,4 +22,38 @@ def is_staff_access(view_to_return="index"): return redirect(view_to_return) return view(request, *args, **kwargs) return _wrapped_view + 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 \ No newline at end of file diff --git a/Clientes/forms.py b/Clientes/forms.py index 22714ab..c95ff05 100644 --- a/Clientes/forms.py +++ b/Clientes/forms.py @@ -10,7 +10,7 @@ class EmailForm(forms.Form): subject = forms.CharField(max_length=100, required=False) adjunto = forms.FileField(widget=forms.ClearableFileInput( attrs={ - 'multiple': True, + 'multiple': True, 'accept':'application/pdf,application/vnd.ms-excel', diff --git a/Clientes/models.py b/Clientes/models.py index a98ba6f..8dcbf9c 100644 --- a/Clientes/models.py +++ b/Clientes/models.py @@ -41,32 +41,27 @@ class Clientes(models.Model): email = models.EmailField(max_length=254, blank=True) conteo_mes = models.IntegerField(blank=True,null=True,default=0) def timbres_X_MES(self, mes): - - today = datetime.date.today() - year = today.year - + today = datetime.date.today() + year = today.year if mes==None: mes = today.month - dat = datetime.datetime(int(year),int(mes),1) - if dat.month in (1,3,5,7,8,10,12):#31 + dat = datetime.datetime(int(year),int(mes),1) + if dat.month in (1,3,5,7,8,10,12):#31 findate = dat + datetime.timedelta(days=30) #findate += datetime.timedelta(days=0) elif dat.month in (4,6,9,11):#30 - 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 += datetime.timedelta(days=1) + findate += datetime.timedelta(days=1) #print(f'dat {(dat)} fdate={findate}') cou = Timbres.objects.filter(rfcc=self.RFC, created_at__range=[dat,findate]).count() - self.conteo_mes =cou self.save() return cou @property - def timbres_mes_count(self): - + def timbres_mes_count(self): today = datetime.date.today() month = today.month year = today.year diff --git a/Clientes/serailizers.py b/Clientes/serailizers.py index 1e62dd8..9e7cab0 100644 --- a/Clientes/serailizers.py +++ b/Clientes/serailizers.py @@ -4,4 +4,4 @@ from .models import Clientes class ClienteSerializer(serializers.ModelSerializer): class Meta: model = Clientes - fields = ('RFC', 'Nombre', 'Activo', 'fecha_baja',) \ No newline at end of file + fields = ('RFC', 'Nombre', 'Activo', 'fecha_baja',) diff --git a/Clientes/urls.py b/Clientes/urls.py index 4f92fe0..76c78ae 100644 --- a/Clientes/urls.py +++ b/Clientes/urls.py @@ -6,6 +6,8 @@ from .views import ( ClientesCreateView, export_Excel, send_timbres_Email, + Retrive_Cliente_Email, + PACS_Retrive_RFCS, #API DRF saldo_funct2, @@ -25,5 +27,6 @@ urlpatterns = [ path('getActivoRFC/', check_RFC.as_view(), name='check_active_RFC'), path('get_saldo2/', saldo_funct2.as_view(), name='saldo_funct2'), 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'), ] \ No newline at end of file diff --git a/Clientes/views.py b/Clientes/views.py index 16746c2..82a9261 100644 --- a/Clientes/views.py +++ b/Clientes/views.py @@ -1,26 +1,29 @@ +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.contrib import messages -from django.http import HttpResponse -from django.http import JsonResponse +from django.http import HttpResponse,JsonResponse 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.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin +from .custom_decorators import is_staff_access, http_basic_auth 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.response import Response from rest_framework.permissions import IsAuthenticated -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 from openpyxl import Workbook from openpyxl.styles import Alignment, Border, Font, PatternFill, Side @@ -29,12 +32,6 @@ from openpyxl.styles import Alignment, Border, Font, PatternFill, Side from django.core.mail import EmailMessage from django.conf import settings 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(): try: @@ -62,6 +59,7 @@ def read_env_file(): @sync_to_async(thread_sensitive=False) @login_required +@is_staff_access() def send_timbres_Email(request): req = request.method @@ -71,6 +69,7 @@ def send_timbres_Email(request): messages.add_message(request, messages.ERROR, f'{form.errors}') return redirect('index') today = datetime.date.today() + year = today.year RFC = request.GET.get('RFC', None) if req=='GET' else form.cleaned_data["RFC"] @@ -98,9 +97,9 @@ def send_timbres_Email(request): else: findate = dat+datetime.timedelta(days=28) findate +=datetime.timedelta(days=1) - print(f'dat{dat} findate:{findate}') + #print(f'dat{dat} findate:{findate}') 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: objeto_a_trabajar = Clientes.objects.all() for i,ii in enumerate(objeto_a_trabajar): @@ -163,6 +162,9 @@ def index(request): #read_env_file() clientes_list = Clientes.objects.all() mes = request.GET.get('mes', None) + today = datetime.date.today() + if mes is None or mes =='None': + mes = today.month page = request.GET.get('page', 1) search = request.GET.get('search',None) rfcc = request.GET.get('rfcc', None) @@ -170,20 +172,19 @@ def index(request): filters.pop('page', '') filters.pop('datepicker','') filters.pop('datepickerFin','') + filters.pop('mes','') print('filters------',filters) if rfcc: clientes_list = Clientes.objects.filter(Q(RFC__icontains=search)) for i,ii in enumerate(clientes_list): ii.timbres_X_MES(mes=mes) clientes_list =pageFunc(page,clientes_list,20) - - filters.pop('mes','') + context = { 'lista':clientes_list, 'mes':mes, 'filters':filters, 'emailForm':EmailForm(), - } return render(request,'Clientes/index.html',context) @@ -202,47 +203,83 @@ def pageFunc(page,qs,per_page): @login_required @is_staff_access() def timbres_cliente(request, RFC): + + if request.user.is_staff: lista = Timbres.objects.filter(rfcc=RFC) else: lista = Timbres.objects.filter(rfcc=RFC,modo='Normal') - + + mes = request.GET.get('mes', None) + today= datetime.date.today() + year =today.year + if mes is None or mes =='None': + mes='00' #Todos + PAC= request.GET.get('PAC',None) - if PAC=='01': - lista = lista.filter(rfcp='EME000602QR9') - if PAC=='02': - lista = lista.exclude(rfcp='EME000602QR9') + # if PAC !="00" or PAC !="None": + # lista = lista.filter(rfcp=str(PAC)) + # else: + # lista = Timbres.objects.filter(rfcc=str(RFC)) + + #print(f'{PAC} filter pro pac',lista.count(), lista) + if PAC is not None and PAC !='00': + lista = lista.filter(rfcp=PAC) + + + + + search = request.GET.get('search',None) page = request.GET.get('page', 1) datepicker = request.GET.get('datepicker', None) datepickerFin = request.GET.get('datepickerFin', None) tipo = request.GET.get('tipo',None) - + + filters = {key:value[0] for (key,value) in dict(request.GET).items() if value !=[""]} + filters.pop('page', '') - filters.pop('PAC', '') - - - if tipo: - lista = lista.filter(Q(tipo__icontains=search)) - - if datepicker and datepickerFin: - inicio = [int(i) for i in datepicker.split("/")] - fin = [int(i) for i in datepickerFin.split("/")] - #print('inicio',inicio,' fin',fin) + if 'PAC' not in filters: + filters['PAC']='00' + if 'mes' not in filters: + filters['mes']='00' + + if tipo and search is not None: + lista = lista.filter(Q(tipo__icontains=search)) + + if datepicker and datepickerFin: + # inicio = [int(i) for i in datepicker.split("/")] + # fin = [int(i) for i in datepickerFin.split("/")] + inicio = [int(i) for i in datepicker.split("-")] + fin = [int(i) for i in datepickerFin.split("-")] + #print('inicio',inicio,' fin',fin) + #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) - 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) - #datetime.date.today() - #print('FECHA',datetime.datetime.today(), 'HORA') - print('start',start, 'end',end) + + #print('start',start, 'end',end) lista = lista.filter(created_at__range=[start, end]) + + 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]) conteo = lista.count() - + print('conteo',conteo) lista =pageFunc(page,lista,50) context ={ @@ -256,6 +293,7 @@ def timbres_cliente(request, RFC): @sync_to_async(thread_sensitive=False) @login_required +@is_staff_access() def export_Excel(request): RFC = request.GET.get('RFC', None) @@ -284,8 +322,6 @@ def export_Excel(request): objeto_a_trabajar = Clientes.objects.all() for i,ii in enumerate(objeto_a_trabajar): ii.timbres_X_MES(mes=mes ) - - wb = Workbook() ws = wb.active @@ -311,11 +347,23 @@ def export_Excel(request): response = HttpResponse(content_type="application/ms-excel") contenido = "attachment; filename = {0}".format(nombre_archivo) response["Content-Disposition"] = contenido - wb.save( response) - + wb.save( 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}) + +def PACS_Retrive_RFCS(request): + status = 302 + timbres = {} + if request.method == 'GET': + timbres =list(Timbres.objects.values('rfcp').filter(rfcp__isnull=False)) + return JsonResponse({'PACS':timbres},status=status) + #-----------------------------------API VIEWS #-------------------------------------------- class check_RFC(APIView): @@ -325,8 +373,7 @@ class check_RFC(APIView): cliente, created = Clientes.objects.get_or_create(RFC=rfc) if created: cliente.Activo=True - cliente.save() - #cliente = get_object_or_404(Clientes, RFC=rfc) + cliente.save() serializer = ClienteSerializer(cliente) return Response(serializer.data) @@ -341,8 +388,7 @@ class add_timbre2(APIView): serie=request.GET.get('serie', None) tipo=request.GET.get('tipo', None) rfcp=request.GET.get('rfcp', None) - modo=request.GET.get('modo', None) - + modo=request.GET.get('modo', None) obj={ 'uuid':uuid, 'rfcc':rfcc, @@ -381,8 +427,7 @@ class saldo_funct2(APIView): return Response(content) class check_host(APIView): - permission_classes = (IsAuthenticated,) - + permission_classes = (IsAuthenticated,) def post(self,request, format=None): data = request.data print(data) @@ -396,13 +441,11 @@ class ClientesUpdateView(UserPassesTestMixin,LoginRequiredMixin,UpdateView): success_url='/' template_name='Clientes/edit_cliente.html' - def test_func(self): - + 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 ClientesCreateView(UserPassesTestMixin,LoginRequiredMixin,CreateView): model = Clientes diff --git a/Templates/Clientes/index.html b/Templates/Clientes/index.html index 195919b..dd511b6 100644 --- a/Templates/Clientes/index.html +++ b/Templates/Clientes/index.html @@ -119,7 +119,7 @@ Timbres disponibles Comercio Digital: {{saldo}} - + +
@@ -161,13 +174,13 @@ Timbres disponibles Comercio Digital: {{saldo}}
- + {{emailForm.adjunto}}
- - + +
+ + + {% endblock content %} {% block scripts %} diff --git a/Templates/Clientes/timbres_cliente.html b/Templates/Clientes/timbres_cliente.html index cd5bbc0..3823952 100644 --- a/Templates/Clientes/timbres_cliente.html +++ b/Templates/Clientes/timbres_cliente.html @@ -25,20 +25,35 @@ PAC - - - + - + Tipo CFDI Serie/Folio - + Fecha + @@ -56,29 +71,125 @@ - + {% endblock content %} {% block scripts %} - + +