first commit

main
Francisco_Borja 1 year ago
commit 21978f7420
  1. 1
      .gitignore
  2. 0
      Inventario/__init__.py
  3. BIN
      Inventario/__pycache__/__init__.cpython-313.pyc
  4. BIN
      Inventario/__pycache__/admin.cpython-313.pyc
  5. BIN
      Inventario/__pycache__/apps.cpython-313.pyc
  6. BIN
      Inventario/__pycache__/forms.cpython-313.pyc
  7. BIN
      Inventario/__pycache__/models.cpython-313.pyc
  8. BIN
      Inventario/__pycache__/views.cpython-313.pyc
  9. BIN
      Inventario/__pycache__/viewspdf.cpython-313.pyc
  10. 3
      Inventario/admin.py
  11. 6
      Inventario/apps.py
  12. 99
      Inventario/forms.py
  13. 76
      Inventario/migrations/0001_initial.py
  14. 138
      Inventario/migrations/0002_rename_descripcion_movimiento_inventario_observaciones_and_more.py
  15. 22
      Inventario/migrations/0003_remove_articulo_codigo_articulo_articulo_medida.py
  16. 0
      Inventario/migrations/__init__.py
  17. BIN
      Inventario/migrations/__pycache__/0001_initial.cpython-313.pyc
  18. BIN
      Inventario/migrations/__pycache__/0002_rename_descripcion_movimiento_inventario_observaciones_and_more.cpython-313.pyc
  19. BIN
      Inventario/migrations/__pycache__/0003_remove_articulo_codigo_articulo_articulo_medida.cpython-313.pyc
  20. BIN
      Inventario/migrations/__pycache__/__init__.cpython-313.pyc
  21. 58
      Inventario/models.py
  22. 105
      Inventario/templates/Base.html
  23. 51
      Inventario/templates/articulo_nuevo.html
  24. 44
      Inventario/templates/articulo_registro.html
  25. 29
      Inventario/templates/articulo_update.html
  26. 51
      Inventario/templates/bodega_nuevo.html
  27. 60
      Inventario/templates/bodega_registro.html
  28. 43
      Inventario/templates/bodega_update.html
  29. 36
      Inventario/templates/grafico_chartjs.html
  30. 181
      Inventario/templates/index.html
  31. 52
      Inventario/templates/inventario_nuevo.html
  32. 45
      Inventario/templates/inventario_registro.html
  33. 41
      Inventario/templates/mov_inventario_registro.html
  34. 36
      Inventario/templates/pdf.html
  35. 56
      Inventario/templates/proveedor_nuevo.html
  36. 56
      Inventario/templates/proveedor_registro.html
  37. 43
      Inventario/templates/proveedor_update.html
  38. 28
      Inventario/templates/signin.html
  39. 44
      Inventario/templates/tipo_articulo_nuevo.html
  40. 51
      Inventario/templates/tipo_articulo_registro.html
  41. 43
      Inventario/templates/tipo_articulo_update.html
  42. 3
      Inventario/tests.py
  43. 338
      Inventario/views.py
  44. 83
      Inventario/viewspdf.py
  45. 2
      TiendAlfa/__init__.py
  46. BIN
      TiendAlfa/__pycache__/__init__.cpython-313.pyc
  47. BIN
      TiendAlfa/__pycache__/settings.cpython-313.pyc
  48. BIN
      TiendAlfa/__pycache__/urls.cpython-313.pyc
  49. BIN
      TiendAlfa/__pycache__/wsgi.cpython-313.pyc
  50. 16
      TiendAlfa/asgi.py
  51. 132
      TiendAlfa/settings.py
  52. 54
      TiendAlfa/urls.py
  53. 16
      TiendAlfa/wsgi.py
  54. 22
      manage.py

1
.gitignore vendored

@ -0,0 +1 @@
venv/

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

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

@ -0,0 +1,99 @@
from django import forms
from .models import proveedor, bodega, tipo_articulo, articulo,inventario,tipo_inv_movimiento
class formulario_proveedor(forms.ModelForm):
class Meta:
model = proveedor
fields = '__all__'
widgets={
'nombre_proveedor': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'Escribe el nombre del proveedor'}),
'email': forms.EmailInput(attrs={'class':'form-control','placeholder':'email del proveedor'}),
'direccion': forms.Textarea(attrs={'class':'form-control','placeholder':'direccion del proveedor','rows':'5'}),
'telefono': forms.TextInput(attrs={'type':'tel','class':'form-control','placeholder':'0000-0000','maxlength':'9' ,'oninput':'formatearInput(this)'}),
}
class formulario_bodega(forms.ModelForm):
class Meta:
model = bodega
fields = '__all__'
widgets={
'nombre_bodega': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'Escribe el nombre de la bodega'}),
'estado': forms.CheckboxInput(attrs={'class':'form-check-input'}),
'direccion_bodega': forms.Textarea(attrs={'class':'form-control','placeholder':'direccion de la bodega','rows':'5'}),
'codigo_bodega': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'Escribe el codigo de la bodega','oninput':'permitirSoloNumeros(this)'}),
}
class formulario_tipo(forms.ModelForm):
class Meta:
model = tipo_articulo
fields = '__all__'
widgets={
'tipo_articulo': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'escriba el tipo de articulo'}),
'descripcion': forms.Textarea(attrs={'class':'form-control','placeholder':'escriba una descripcion de este tipo de articulo','rows':'5'}),
}
class formulario_articulo(forms.ModelForm):
tipo_articulo=forms.ModelChoiceField(queryset=tipo_articulo.objects.all(),
empty_label="Selecciona un tipo de articulo",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="tipo_articulo")
proveedor=forms.ModelChoiceField(queryset=proveedor.objects.all(),
empty_label="Selecciona un proveedor",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle ', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="proveedor")
class Meta:
model = articulo
fields = '__all__'
widgets={
'nombre_articulo': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'escriba el nombre del articulo'}),
'medida': forms.TextInput(attrs={'class':'form-control','placeholder':'medida del producto lts, cm, etc'}),
'descripcion': forms.Textarea(attrs={'class':'form-control','placeholder':'describa el producto','rows':'5'}),
}
class formilario_inventarios(forms.ModelForm):
articulo=forms.ModelChoiceField(queryset=articulo.objects.all(),
empty_label="selecciones un articulo",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="articulo")
bodega=forms.ModelChoiceField(queryset=bodega.objects.all(),
empty_label="Selecciona una bodega",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle ', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="bodega")
class Meta:
model = inventario
fields = '__all__'
widgets={
'cantidad': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'Cantidad de productos','oninput':'permitirSoloNumeros(this)',}),
'precio': forms.NumberInput(attrs={'class':'form-control','placeholder':'Ej: 99.99','step': '0.01','min':'0','max':'10000',}),
}
class formilario_inventario(forms.ModelForm):
tipo_inventario=forms.ModelChoiceField(queryset=tipo_inv_movimiento.objects.all(),
empty_label="selecciones un articulo",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="tipo de inventario")
bodega=forms.ModelChoiceField(queryset=bodega.objects.all(),
empty_label="Selecciona una bodega",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle ', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="bodega")
articulo=forms.ModelChoiceField(queryset=articulo.objects.all(),
empty_label="Selecciona una bodega",
widget=forms.Select(attrs={'class': 'btn btn-secondary dropdown-toggle ', 'data-bs-toggle': 'dropdown', 'aria-expanded': 'false'}),
label="articulo")
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Personaliza cómo se muestran las opciones en el dropdown
self.fields['articulo'].label_from_instance = lambda obj: f"{obj.nombre_articulo} ({obj.medida})" if obj.medida else obj.nombre_articulo
self.fields['bodega'].label_from_instance = lambda obj: f"{obj.nombre_bodega} ({obj.codigo_bodega})" if obj.codigo_bodega else obj.nombre_bodega
class Meta:
model = inventario
fields = '__all__'
widgets={
'fecha': forms.DateInput(attrs={'type': 'date','class': 'form-control','placeholder': 'Seleccione una fecha'}),
'precio': forms.NumberInput(attrs={'class':'form-control','placeholder':'Ej: 99.99','step': '0.01','min':'0','max':'10000',}),
'cantidad': forms.TextInput(attrs={'class': 'form-control' , 'placeholder': 'Cantidad de productos','oninput':'permitirSoloNumeros(this)',}),
'observacion': forms.Textarea(attrs={'class':'form-control','placeholder':'observacion','rows':'5'}),
}

@ -0,0 +1,76 @@
# Generated by Django 5.1.4 on 2024-12-11 06:38
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='bodega',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('codigo_bodega', models.IntegerField()),
('nombre_bodega', models.CharField(max_length=40)),
('estado', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='proveedor',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nombre_proveedor', models.CharField(max_length=100)),
('email', models.EmailField(blank=True, max_length=254, null=True)),
('telefono', models.CharField(blank=True, max_length=20, null=True)),
('direccion', models.TextField(blank=True, null=True)),
('estado', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='tipo_articulo',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tipo_articulo', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='tipo_inv_movimiento',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('tipo_movimiento', models.CharField(max_length=100)),
],
),
migrations.CreateModel(
name='articulo',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nombre_articulo', models.CharField(max_length=100)),
('precio_articulo', models.DecimalField(decimal_places=2, max_digits=10)),
('stock', models.IntegerField()),
('creado', models.DateTimeField(auto_now_add=True)),
('actualizado', models.DateTimeField(auto_now=True)),
('activo', models.BooleanField(default=True)),
('bodega', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bodega', to='Inventario.bodega')),
('proveedor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='productos', to='Inventario.proveedor')),
],
),
migrations.CreateModel(
name='movimiento_inventario',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cantidad', models.IntegerField()),
('descripcion', models.TextField(blank=True)),
('total_costo', models.DecimalField(decimal_places=2, max_digits=10)),
('numero_mov', models.IntegerField()),
('fecha', models.DateTimeField(auto_now_add=True)),
('articulo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='articulos', to='Inventario.articulo')),
('tipo_movimiento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mov_inv', to='Inventario.tipo_inv_movimiento')),
],
),
]

@ -0,0 +1,138 @@
# Generated by Django 5.1.4 on 2024-12-13 02:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Inventario', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='movimiento_inventario',
old_name='descripcion',
new_name='observaciones',
),
migrations.RenameField(
model_name='movimiento_inventario',
old_name='total_costo',
new_name='precio',
),
migrations.RemoveField(
model_name='articulo',
name='activo',
),
migrations.RemoveField(
model_name='articulo',
name='actualizado',
),
migrations.RemoveField(
model_name='articulo',
name='bodega',
),
migrations.RemoveField(
model_name='articulo',
name='creado',
),
migrations.RemoveField(
model_name='articulo',
name='precio_articulo',
),
migrations.RemoveField(
model_name='articulo',
name='stock',
),
migrations.RemoveField(
model_name='movimiento_inventario',
name='numero_mov',
),
migrations.RemoveField(
model_name='movimiento_inventario',
name='tipo_movimiento',
),
migrations.RemoveField(
model_name='proveedor',
name='estado',
),
migrations.AddField(
model_name='articulo',
name='codigo_articulo',
field=models.IntegerField(null=True),
),
migrations.AddField(
model_name='articulo',
name='descripcion',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='articulo',
name='tipo_articulo',
field=models.ForeignKey(default=40, on_delete=django.db.models.deletion.CASCADE, to='Inventario.tipo_articulo'),
preserve_default=False,
),
migrations.AddField(
model_name='bodega',
name='direccion_bodega',
field=models.TextField(blank=True),
),
migrations.AddField(
model_name='movimiento_inventario',
name='bodega',
field=models.ForeignKey(default=60, on_delete=django.db.models.deletion.CASCADE, to='Inventario.bodega'),
preserve_default=False,
),
migrations.AddField(
model_name='movimiento_inventario',
name='tipo_inventario',
field=models.ForeignKey(default=100, on_delete=django.db.models.deletion.CASCADE, to='Inventario.tipo_inv_movimiento'),
preserve_default=False,
),
migrations.AddField(
model_name='tipo_articulo',
name='descripcion',
field=models.TextField(blank=True),
),
migrations.AlterField(
model_name='articulo',
name='proveedor',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Inventario.proveedor'),
),
migrations.AlterField(
model_name='bodega',
name='codigo_bodega',
field=models.IntegerField(null=True),
),
migrations.AlterField(
model_name='movimiento_inventario',
name='articulo',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Inventario.articulo'),
),
migrations.AlterField(
model_name='movimiento_inventario',
name='cantidad',
field=models.IntegerField(null=True),
),
migrations.AlterField(
model_name='movimiento_inventario',
name='fecha',
field=models.DateTimeField(null=True),
),
migrations.AlterField(
model_name='tipo_articulo',
name='tipo_articulo',
field=models.CharField(max_length=40),
),
migrations.CreateModel(
name='inventario',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cantidad', models.IntegerField(null=True)),
('precio', models.DecimalField(decimal_places=2, max_digits=10)),
('articulo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Inventario.articulo')),
('bodega', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='Inventario.bodega')),
],
),
]

@ -0,0 +1,22 @@
# Generated by Django 5.1.4 on 2024-12-15 18:34
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('Inventario', '0002_rename_descripcion_movimiento_inventario_observaciones_and_more'),
]
operations = [
migrations.RemoveField(
model_name='articulo',
name='codigo_articulo',
),
migrations.AddField(
model_name='articulo',
name='medida',
field=models.CharField(blank=True, max_length=100, null=True),
),
]

@ -0,0 +1,58 @@
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class tipo_articulo(models.Model):
tipo_articulo= models.CharField(max_length=40)
descripcion=models.TextField(blank=True)
def __str__(self):
return self.tipo_articulo
class proveedor(models.Model):
nombre_proveedor=models.CharField(max_length=100)
email = models.EmailField(null=True, blank=True)
telefono = models.CharField(max_length=20, null=True, blank=True)
direccion = models.TextField(null=True, blank=True)
def __str__(self):
return self.nombre_proveedor
class tipo_inv_movimiento(models.Model):
tipo_movimiento=models.CharField(max_length=100)
def __str__(self):
return self.tipo_movimiento
class bodega(models.Model):
codigo_bodega=models.IntegerField(null=True)
nombre_bodega= models.CharField(max_length=40)
direccion_bodega=models.TextField(blank=True)
estado= models.BooleanField(default=True)
def __str__(self):
return self.nombre_bodega
class articulo(models.Model):
nombre_articulo=models.CharField(max_length=100)
medida = models.CharField(max_length=100, blank=True, null=True)
descripcion = models.TextField(blank=True)
proveedor = models.ForeignKey(proveedor, on_delete=models.CASCADE)
tipo_articulo=models.ForeignKey(tipo_articulo, on_delete=models.CASCADE)
def __str__(self):
return self.nombre_articulo
class inventario(models.Model):
bodega=models.ForeignKey(bodega, on_delete=models.CASCADE)
articulo=models.ForeignKey(articulo, on_delete=models.CASCADE)
cantidad=models.IntegerField(null=True)
precio=models.DecimalField( max_digits=10, decimal_places=2)
class movimiento_inventario(models.Model):
fecha=models.DateTimeField(null=True)
tipo_inventario=models.ForeignKey(tipo_inv_movimiento,on_delete=models.CASCADE)
bodega=models.ForeignKey(bodega, on_delete=models.CASCADE)
articulo=models.ForeignKey(articulo, on_delete=models.CASCADE)
cantidad=models.IntegerField(null=True)
precio=models.DecimalField(max_digits=10, decimal_places=2)
observaciones=models.TextField(blank=True)

@ -0,0 +1,105 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tienda la esquina</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<nav class="navbar bg-dark navbar-dark">
<div class="container-fluid ">
<a class="navbar-brand " href="/">Tienda la esquina</a>
<button class="navbar-toggler " type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="offcanvas offcanvas-end bg-dark navbar-dark" tabindex="-1" id="offcanvasNavbar" aria-labelledby="offcanvasNavbarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title"style="color:white;" id="offcanvasNavbarLabel">Bienvenido {{user.username}}</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav justify-content-end flex-grow-1 pe-3">
<a style="color:white;"></a>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="/">Home</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item dropdown ">
<a class="nav-link dropdown-toggle " role="button" data-bs-toggle="dropdown" aria-expanded="false">
Gestores
</a>
<ul class="dropdown-menu dropdown-menu-dark">
<li>
<p class="nav-link disabled text-center" aria-disabled="true">Gestor de proveedores</p>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="{% url 'proveedor' %}">Lista de proveedores</a></li>
<li><a class="dropdown-item" href="{% url 'proveedor_registro' %}">Registro de proveedores</li>
<li>
<hr class="dropdown-divider">
<a class="nav-link disabled text-center" aria-disabled="true">Gestor de bodegas</a>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="{% url 'bodega_vista' %}">Lista de Bodegas</a></li>
<li><a class="dropdown-item" href="{% url 'bodega_registro' %}">Registro de bodegas</li>
<li>
<hr class="dropdown-divider">
<a class="nav-link disabled text-center" aria-disabled="true">Gestor de tipos de articulo</a>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="{% url 'tipo_vista' %}">Lista de tipos de articulos</a></li>
<li><a class="dropdown-item" href="{% url 'tipo_registro' %}">Registro de tipos de articulos</li>
</ul>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'articulo_vista' %}">Articulos</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'inventario_vista' %}">inventario</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'vista_inventario_mov' %}">movimiento de inventario</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'logout' %}">logout</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'signin' %}">login</a>
</li>
{% endif %}
</ul>
</div>
</div>
</div>
</nav>
{% block content %}
{% endblock %}
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</body>
</html>

@ -0,0 +1,51 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form action="/articulo/crear/" method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'articulo_vista' %}"><- volver</a>
<h3 class="col-5">Registro articulo</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form.as_p}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">Crear nuevo articulo</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
<script>
function permitirSoloNumeros(input) {
input.value = input.value.replace(/[^0-9]/g, '');
}
</script>
{% endblock %}

@ -0,0 +1,44 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/articulo/" method="POST">
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Vista articulo</h3>
<a class="btn btn-success col-md-3" href="{% url 'articulo_registro' %}">Nuevo articulo</a>
</div>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">nombre del articulo</th>
<th scope="col">medida</th>
<th scope="col">descripcion</th>
<th scope="col">tipo_articulo</th>
<th scope="col">proveedors</th>
<th scope="col">actualizar</th>
</tr>
</thead>
<tbody>
{% for articulo in persona %}
<tr>
<th scope="row">{{ articulo.id }}</th>
<td> {{ articulo.nombre_articulo }} </td>
<td> {{ articulo.medida }} </td>
<td> {{ articulo.descripcion }} </td>
<td> {{ articulo.tipo_articulo.tipo_articulo }} </td>
<td> {{ articulo.proveedor.nombre_proveedor }} </td>
<td> <a class="btn btn-warning" href="{% url 'articulo_update' articulo.id %}">Editar</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,29 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'articulo_vista' %}"><- volver</a>
<h3 class="col-5">Actualizar articulo</h3>
</div>
<div class="card-body">
{% csrf_token %}
{{form.as_p}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">actualizar datos de articulo</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,51 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form action="/bodega/crearbodega/" method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'bodega_vista' %}"> <- volver</a>
<h3 class="col-5">Registro bodega</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">Crear nueva bodega</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
<script>
function permitirSoloNumeros(input) {
input.value = input.value.replace(/[^0-9]/g, '');
}
</script>
{% endblock %}

@ -0,0 +1,60 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/bodega/" method="POST">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Vista Bodega</h3>
<a class="btn btn-success col-md-3" href="{% url 'bodega_registro' %}">Nueva bodega</a>
</div>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">codigo de la bodega</th>
<th scope="col">nombre del supervisor</th>
<th scope="col">estado</th>
<th scope="col">Direccion</th>
<th scope="col">Editar</th>
</tr>
</thead>
<tbody>
{% for bodega in persona %}
<tr>
<th scope="row"> {{bodega.id}} </th>
<td> {{bodega.codigo_bodega}} </td>
<td> {{bodega.nombre_bodega}} </td>
{% if bodega.estado %}
<td> activo </td>
{% else %}
<td> inactivo </td>
{% endif %}
<td> {{bodega.direccion_bodega}} </td>
<td> <a class="btn btn-warning" href="{% url 'bodega_update' bodega.id %}">Editar</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,43 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'bodega_vista' %}"><- volver</a>
<h3 class="col-5">Actualizar bodega</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
bodega a sido actualizado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">actualizar datos de proveedor</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<title>Gráfico Interactivo</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<h1>Gráfico de cantidad de productos</h1>
<canvas id="grafico" width="400" height="200"></canvas>
<script>
const ctx = document.getElementById('grafico').getContext('2d');
const myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: {{ productos|safe }}, // Nombres de los productos
datasets: [{
label: 'Cantidad de Productos',
data: {{ cantidades|safe }}, // Cantidades de productos
backgroundColor: 'rgba(75, 192, 192, 0.2)',
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
<a href="{% url 'inventario_vista' %}" class="btn btn-secondary">volver</a>
</body>
</html>

@ -0,0 +1,181 @@
{% extends "Base.html" %}
{% block content %}
{% if user.is_authenticated %}
<main class="conteiner col-md-10 offset-md-1 mt-5 g-4">
<div class="row row-cols-1 row-cols-md-2 g-4">
<div class="col">
<div class="card h-100">
<div class="card-body">
<p class="text-center">Precio promedio de cada tipo articulo</p>
<div class="chart-container">
<canvas id="avgPriceChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-body">
<p class="text-center">articulos en bodegas</p>
<div class="chart-container">
<canvas id="barChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-body">
<p class="text-center">Cantidad de tipos de articulos</p>
<div class="chart-container">
<canvas id="graficoLinealMovimientos"></canvas>
</div>
<br>
<div class="text-center">
<p class="text-center">Reportes del inventario</p>
<a href="{% url 'generar_reporte_pdf' %}" class="btn btn-primary">Descargar PDF</a>
<a href="{% url 'generar_reporte_excel' %}" class="btn btn-success">Descargar Excel</a>
<a href="{% url 'generar_reporte_csv' %}" class="btn btn-info">Descargar CSV</a>
</div>
<br>
<p class="text-center">Grafico de productos</p>
<div class="text-center">
<a href="{% url 'generar_grafico_chartjs' %}" class="btn btn-secondary">generar grafico de produccion</a>
</div>
</div>
</div>
</div>
<div class="col">
<div class="card h-100">
<div class="card-body">
<p class="text-center">Cantidad de tipos de articulos</p>
<div class="chart-container">
<canvas id="pieChart"></canvas>
</div>
</div>
</div>
</div>
</main>
<script>
// Datos dinámicos generados desde Django
const tiposArticulo = {{ tipos_articulo | safe }};
const cantidadesPorTipo = {{ cantidades_por_tipo | safe }};
const bodegas = {{ bodegas | safe }};
const cantidadesPorBodega = {{ cantidades_por_bodega | safe }};
const tiposArticuloProm = {{ tipos_articulo_prom | safe }};
const preciosPromedio = {{ precios_promedio | safe }};
// 1. Gráfico de Pastel: Distribución de artículos por tipo
new Chart(document.getElementById('pieChart').getContext('2d'), {
type: 'pie',
data: {
labels: tiposArticulo,
datasets: [{
data: cantidadesPorTipo,
backgroundColor: ['rgba(255, 99, 132, 0.6)', 'rgba(54, 162, 235, 0.6)', 'rgba(255, 206, 86, 0.6)', 'rgba(75, 192, 192, 0.6)'],
}]
},
options: {
responsive: true,
plugins: {
legend: { position: 'top' },
}
}
});
// 2. Gráfico de Barras: Cantidad de artículos por bodega
new Chart(document.getElementById('barChart').getContext('2d'), {
type: 'bar',
data: {
labels: bodegas,
datasets: [{
label: 'Cantidad de Artículos',
data: cantidadesPorBodega,
backgroundColor: 'rgba(75, 192, 192, 0.6)',
}]
},
options: {
responsive: true,
plugins: {
legend: { display: false },
},
scales: {
x: { title: { display: true, text: 'Bodegas' } },
y: { title: { display: true, text: 'Cantidad' } },
}
}
});
// 3. Gráfico de Línea: Evolución de movimientos de inventario
new Chart(document.getElementById('avgPriceChart').getContext('2d'), {
type: 'bar',
data: {
labels: tiposArticuloProm,
datasets: [{
label: 'Precio Promedio',
data: preciosPromedio,
backgroundColor: 'rgba(255, 159, 64, 0.6)',
}]
},
options: {
responsive: true,
plugins: {
legend: { position: 'top' },
},
scales: {
x: { title: { display: true, text: 'Tipos de Artículos' } },
y: { title: { display: true, text: 'Precio Promedio' } },
}
}
});
const ctx = document.getElementById('graficoLinealMovimientos').getContext('2d');
const graficoLineal = new Chart(ctx, {
type: 'line',
data: {
labels: {{ nombres_tipos|safe }}, // Nombres de los tipos de movimientos
datasets: [{
label: 'Cantidad Total Movida',
data: {{ cantidades_por_tipos|safe }}, // Cantidades totales por tipo de movimiento
borderColor: 'rgba(54, 162, 235, 1)',
backgroundColor: 'rgba(54, 162, 235, 0.2)',
borderWidth: 2,
tension: 0.3, // Para suavizar la línea
}]
},
options: {
responsive: true,
plugins: {
legend: {
display: true,
},
tooltip: {
enabled: true,
}
},
scales: {
x: {
title: {
display: true,
text: 'Tipos de Movimiento'
}
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Cantidad Total'
}
}
}
}
});
</script>
{% else %}
{% endif %}
{% endblock %}

@ -0,0 +1,52 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form action="/inventariomov/crear/" method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'vista_inventario_mov' %}"><- volver</a>
<h3 class="col-5">Registro inventario</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
inventario a sido creado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form.as_p}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">Crear nuevo inventario</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
<script>
function permitirSoloNumeros(input) {
input.value = input.value.replace(/[^0-9]/g, '');
}
</script>
{% endblock %}

@ -0,0 +1,45 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/inventario/" method="POST">
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Vista inventario</h3>
</div>
<a href="{% url 'generar_reporte_pdf' %}" class="btn btn-primary">Descargar PDF</a>
<a href="{% url 'generar_reporte_excel' %}" class="btn btn-success">Descargar Excel</a>
<a href="{% url 'generar_reporte_csv' %}" class="btn btn-info">Descargar CSV</a>
<a href="{% url 'generar_grafico_chartjs' %}" class="btn btn-secondary">grafico</a>
<br>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">articulo</th>
<th scope="col">Descripcion de articulo</th>
<th scope="col">bodega</th>
<th scope="col">cantidad</th>
<th scope="col">precio</th>
</tr>
</thead>
<tbody>
{% for inventario in persona %}
<tr>
<th scope="row">{{ inventario.id }}</th>
<td> {{ inventario.articulo.nombre_articulo }} {{inventario.articulo.medida}} </td>
<td> {{ inventario.articulo.descripcion }} </td>
<td> {{ inventario.bodega.nombre_bodega }} </td>
<td> {{ inventario.cantidad }} </td>
<td> {{ inventario.precio }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,41 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/inventariomov/" method="POST">
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Vista inventario</h3>
<a class="btn btn-success col-md-3" href="{% url 'registrar_movimiento' %}"> Nuevo movimiento de inventario</a>
</div>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">bodega</th>
<th scope="col">articulo</th>
<th scope="col">cantidad</th>
<th scope="col">precio</th>
<th scope="col">tipo de movimiento</th>
</tr>
</thead>
<tbody>
{% for movimiento_inventario in persona %}
<tr>
<th scope="row">{{ movimiento_inventario.id }}</th>
<td> {{ movimiento_inventario.articulo.nombre_articulo }} {{movimiento_inventario.articulo.medida}} </td>
<td> {{ movimiento_inventario.bodega.nombre_bodega }} </td>
<td> {{ movimiento_inventario.cantidad }} </td>
<td> {{ movimiento_inventario.precio }} </td>
<td> {{ movimiento_inventario.tipo_inventario }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; }
table { width: 100%; border-collapse: collapse; margin-top: 20px; }
th, td { border: 1px solid #000; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>Reporte de Inventario</h1>
<table>
<thead>
<tr>
<th>ID</th>
<th>Bodega</th>
<th>Artículo</th>
<th>Cantidad</th>
<th>Precio</th>
</tr>
</thead>
<tbody>
{% for item in inventarios %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.bodega.nombre_bodega }}</td>
<td>{{ item.articulo.nombre_articulo }}</td>
<td>{{ item.cantidad }}</td>
<td>{{ item.precio }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>

@ -0,0 +1,56 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form action="/proveedor/crear/" method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'proveedor' %}"><- volver</a>
<h3 class="col-5">Registro Proveedor</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">Crear nuevo proveedor</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
<script>
function formatearInput(input) {
// Remover caracteres no numéricos
let valor = input.value.replace(/[^0-9]/g, '');
// Insertar el guion después de los primeros 4 dígitos
if (valor.length > 4) {
valor = valor.slice(0, 4) + '-' + valor.slice(4);
}
input.value = valor;
}
</script>
{% endblock %}

@ -0,0 +1,56 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/proveedor/" method="POST">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Proveedores</h3>
<a class="btn btn-success col-md-3" href="{% url 'proveedor_registro' %}">Nuevo proveedor</a>
</div>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Nombre</th>
<th scope="col">Email</th>
<th scope="col">Telefono</th>
<th scope="col">Direccion</th>
<th scope="col">Editar</th>
</tr>
</thead>
<tbody>
{% for proveedor in persona %}
<tr>
<th scope="row"> {{proveedor.id}} </th>
<td> {{proveedor.nombre_proveedor}} </td>
<td> {{proveedor.email}} </td>
<td> {{proveedor.telefono}} </td>
<td> {{proveedor.direccion}} </td>
<td> <a class="btn btn-warning" href="{% url 'Proveedor_update' proveedor.id %}">Editar</a> </td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,43 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'proveedor' %}"><- volver</a>
<h3 class="col-5">Actualizar Proveedor</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido actualizado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">actualizar datos de proveedor</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,28 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-4 offset-md-4 mt-5">
<form action="/signin/" method="POST" class="card card-body">
<h1 class="text-center">Login</h1>
{% csrf_token %}
<div class="mb-3">
<label for="username"> Usuario:</label>
<input type="text" name="username" id="username"
class="form-control" placeholder="Escribe tu usuario">
</div>
<div class="mb-3">
<label for="password"> Contraseña:</label>
<input type="password" name="password" id="password"
class="form-control" placeholder="escribe tu contraseña">
</div>
<button class="btn btn-primary"> Signin </button>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,44 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form action="/tipo/creartipo_articulo/" method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'tipo_vista' %}"><- volver</a>
<h3 class="col-5">Registro tipo articulo</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
el tipo de articulo a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">Crear nuevo tipo de articulo</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,51 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-10 offset-md-1 mt-4">
<form action="/tipo/" method="POST">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
Proveedor a sido guardado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
<div class="card-header row col-12 justify-content-end mb-2 pr-0 mt-2">
<h3 class="col-md-4">Tipos de articulos</h3>
<a class="btn btn-success col-md-3" href="{% url 'tipo_registro' %}">Nuevo tipo de articulo</a>
</div>
<table class="table mt-3">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">tipo de articulo</th>
<th scope="col">Descripcion</th>
<th scope="col">Actualizar</th>
</tr>
</thead>
<tbody>
{% for tipo_articulo in persona %}
<tr>
<th scope="row"> {{tipo_articulo.id}} </th>
<td> {{tipo_articulo.tipo_articulo}} </td>
<td> {{tipo_articulo.descripcion}} </td>
<td> <a class="btn btn-warning" href="{% url 'tipo_update' tipo_articulo.id %}">Editar</a> </td> </tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
</div>
</main>
{% endblock %}

@ -0,0 +1,43 @@
{% extends "Base.html" %}
{% block content %}
<main class="conteiner">
<div class="row">
<div class="col-md-8 offset-md-2 mt-4">
<form method="POST">
<div class="card">
<div class="card-header row col-12 justify-content-start mb-2 pr-0 mt-2">
<a class="btn btn-danger col-3" href="{% url 'tipo_vista' %}"><- volver</a>
<h3 class="col-5">Actualizar tipo de articulo</h3>
</div>
<div class="card-body">
{% if error %}
<div class="alert alert-danger" role="alert">
{{error}}
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button> </div>
{% endif %}
{% if mensaje %}
<div class="alert alert-success" role="alert">
tipo de articulo a sido actualizado con exito
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
{% endif %}
{% csrf_token %}
{{form}}
<div class="d-grid gap-2 col-6 mx-auto mt-3">
<button class="btn btn-primary btn-lg ">actualizar datos de tipo articulo</button>
</div>
</div>
</div>
</form>
</div>
</div>
</main>
{% endblock %}

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

@ -0,0 +1,338 @@
from django.shortcuts import render,redirect,get_object_or_404
from django.template.loader import get_template
from django.http import HttpResponse
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import login, logout, authenticate
from django.db import transaction
from django.utils import timezone
from django.contrib.auth.decorators import login_required
from django.db.models import Avg, Sum
from decimal import Decimal
from .forms import formulario_proveedor,formulario_bodega, formulario_tipo, formulario_articulo,formilario_inventario
from .models import proveedor, bodega, tipo_articulo, articulo,inventario,tipo_inv_movimiento,movimiento_inventario
# Create your views here.
def base(request):
return render(request, 'index.html')
def generar_grafico_chartjs(request):
# Gráfico de Pastel: Cantidad por tipo de artículo
tipos_articulo = tipo_articulo.objects.all()
tipos_nombres = [t.tipo_articulo for t in tipos_articulo]
cantidades_por_tipo = [articulo.objects.filter(tipo_articulo=t).count() for t in tipos_articulo]
# Gráfico de Barras: Cantidad de artículos por bodega
bodegas = bodega.objects.all()
bodegas_nombres = [b.nombre_bodega for b in bodegas]
cantidades_por_bodega = [inventario.objects.filter(bodega=b).count() for b in bodegas]
# Gráfico de Línea: Movimientos en el tiempo
tipos_movimientos = tipo_inv_movimiento.objects.all()
nombres_tipos = [mov.tipo_movimiento for mov in tipos_movimientos]
# Obtener la cantidad total movida para cada tipo de movimiento
cantidades_por_tipos = [
movimiento_inventario.objects.filter(tipo_inventario=mov).aggregate(total=Sum('cantidad'))['total'] or 0
for mov in tipos_movimientos
]
tipos_articulo_prom = [t.tipo_articulo for t in tipos_articulo]
precios_promedio = [
float(inventario.objects.filter(articulo__tipo_articulo=t).aggregate(avg=Avg('precio'))['avg'] or 0)
for t in tipos_articulo
]
context = {
'tipos_articulo': tipos_nombres,
'cantidades_por_tipo': cantidades_por_tipo,
'bodegas': bodegas_nombres,
'cantidades_por_bodega': cantidades_por_bodega,
'tipos_articulo_prom': tipos_articulo_prom,
'precios_promedio': precios_promedio,
'nombres_tipos': nombres_tipos,
'cantidades_por_tipos': cantidades_por_tipos,
}
return render(request, 'index.html', context)
def signin(request):
if request.method == 'GET':
return render ( request, 'signin.html',{
'form': AuthenticationForm
})
else:
user=authenticate(request, username=request.POST['username'], password=request.POST['password'])
if user is None:
return render ( request, 'signin.html',{
'form': AuthenticationForm ,
'error': 'Username or password is incorrect'
})
else:
login(request, user)
return redirect('home')
@login_required
def signout(request):
logout(request)
return redirect('home')
@login_required
def proveedor_registro(request):
if request.method=='GET':
return render(request, 'proveedor_nuevo.html',{
'form': formulario_proveedor
})
else:
try:
form = formulario_proveedor (request.POST)
form.save()
form = formulario_proveedor ()
return render(request, 'proveedor_nuevo.html',{
'form': formulario_proveedor,
'mensaje':'Please provide valid data'
})
except ValueError:
return render(request, 'proveedor_nuevo.html',{
'form': formulario_proveedor,
'error':'Please provide valid data'
})
@login_required
def proveedor_lista(request):
persona = proveedor.objects.all
return render(request,"proveedor_registro.html", {'persona':persona})
@login_required
def Proveedor_update(request,task_id):
if request.method == 'GET':
tarea = get_object_or_404 (proveedor, pk=task_id)
form = formulario_proveedor(instance=tarea)
return render(request, 'proveedor_update.html',{'tasks':tarea, 'form':form} )
else:
try:
tarea=get_object_or_404(proveedor,pk=task_id)
form = formulario_proveedor(request.POST, instance=tarea)
form.save()
return redirect('proveedor')
except ValueError:
return render(request, 'proveedor_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} )
@login_required
def bodega_registro(request):
if request.method=='GET':
return render(request, 'bodega_nuevo.html',{
'form': formulario_bodega
})
else:
try:
form = formulario_bodega (request.POST)
form.save()
form = formulario_bodega ()
return render(request, 'bodega_nuevo.html',{
'form': formulario_bodega,
'mensaje':'Please provide valid data'
})
except ValueError:
return render(request, 'bodega_nuevo.html',{
'form': formulario_bodega,
'error':'Please provide valid data'
})
@login_required
def bodega_vista(request):
persona = bodega.objects.all
return render(request,"bodega_registro.html", {'persona':persona})
@login_required
def bodega_update(request,task_id):
if request.method == 'GET':
tarea = get_object_or_404 (bodega, pk=task_id)
form = formulario_bodega(instance=tarea)
return render(request, 'bodega_update.html',{'tasks':tarea, 'form':form} )
else:
try:
tarea=get_object_or_404(bodega,pk=task_id)
form = formulario_bodega(request.POST, instance=tarea)
form.save()
return redirect('bodega_vista')
except ValueError:
return render(request, 'bodega_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} )
@login_required
def tipo_registro(request):
if request.method=='GET':
return render(request, 'tipo_articulo_nuevo.html',{
'form': formulario_tipo
})
else:
try:
form = formulario_tipo (request.POST)
form.save()
form = formulario_tipo ()
return render(request, 'tipo_articulo_nuevo.html',{
'form': formulario_tipo,
'mensaje':'Please provide valid data'
})
except ValueError:
return render(request, 'tipo_articulo_nuevo.html',{
'form': formulario_tipo,
'error':'Please provide valid data'
})
@login_required
def tipo_vista(request):
persona = tipo_articulo.objects.all
return render(request,"tipo_articulo_registro.html", {'persona':persona})
@login_required
def tipo_update(request,task_id):
if request.method == 'GET':
tarea = get_object_or_404 (tipo_articulo, pk=task_id)
form = formulario_tipo(instance=tarea)
return render(request, 'tipo_articulo_update.html',{'tasks':tarea, 'form':form} )
else:
try:
tarea=get_object_or_404(tipo_articulo,pk=task_id)
form = formulario_tipo(request.POST, instance=tarea)
form.save()
return redirect('tipo_vista')
except ValueError:
return render(request, 'tipo_articulo_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating task'} )
@login_required
def articulo_registro(request):
if request.method=='GET':
return render(request, 'articulo_nuevo.html',{
'form': formulario_articulo
})
else:
try:
form = formulario_articulo (request.POST)
form.save()
form = formulario_articulo ()
return redirect('articulo_registro')
except ValueError:
return render(request, 'articulo_nuevo.html',{
'form': formulario_articulo,
'error':'Please provide valid data'
})
@login_required
def articulo_vista(request):
persona = articulo.objects.select_related('tipo_articulo','proveedor').all()
return render(request,"articulo_registro.html", {'persona':persona})
@login_required
def articulo_update(request,task_id):
if request.method == 'GET':
tarea = get_object_or_404 (articulo, pk=task_id)
form = formulario_articulo(instance=tarea)
return render(request, 'articulo_update.html',{'tasks':tarea, 'form':form} )
else:
try:
tarea=get_object_or_404(articulo,pk=task_id)
form = formulario_articulo(request.POST, instance=tarea)
form.save()
return redirect('articulo_vista')
except ValueError:
return render(request, 'articulo_update.html',{'tasks':tarea, 'form':form, 'error': 'error updating'} )
@login_required
def inventario_registro(request):
if request.method=='GET':
return render(request, 'inventario_nuevo.html',{
'form': formilario_inventario
})
else:
try:
form = formilario_inventario (request.POST)
form.save()
form = formilario_inventario ()
return render(request, 'inventario_nuevo.html',{
'form': formilario_inventario,
'mensaje':'Please provide valid data'
})
except ValueError:
return render(request, 'inventario_nuevo.html',{
'form': formilario_inventario,
'error':'Please provide valid data'
})
@login_required
def inventario_vista(request):
persona = inventario.objects.select_related('articulo','bodega').all()
return render(request,"inventario_registro.html", {'persona':persona})
def registrar_movimiento_y_actualizar_inventario(movimiento_data):
"""
Registra un movimiento de inventario y actualiza el inventario relacionado.
"""
try:
with transaction.atomic():
# Registrar el movimiento de inventario
movimiento = movimiento_inventario.objects.create(
articulo=movimiento_data['articulo'],
bodega=movimiento_data['bodega'],
tipo_inventario=movimiento_data['tipo_inventario'],
cantidad=movimiento_data['cantidad'],
precio=movimiento_data['precio'],
observaciones=movimiento_data.get('observaciones', '')
)
# Buscar o crear el inventario correspondiente
inventario_obj, created = inventario.objects.get_or_create(
articulo=movimiento.articulo,
bodega=movimiento.bodega,
defaults={'cantidad': 0, 'precio': movimiento.precio}
)
# Actualizar stock según el tipo de movimiento
if movimiento.tipo_inventario.id == 1: # Asegúrate de que 'nombre' sea un campo válido
inventario_obj.cantidad += movimiento.cantidad
elif movimiento.tipo_inventario.id == 2:
if inventario_obj.cantidad < movimiento.cantidad:
raise ValueError(
f"No hay suficiente stock. Disponible: {inventario_obj.cantidad}, solicitado: {movimiento.cantidad}"
)
inventario_obj.cantidad -= movimiento.cantidad
# Actualizar el precio en Inventario si es necesario
if inventario_obj.precio != movimiento.precio:
inventario_obj.precio = movimiento.precio
# Guardar los cambios en el inventario
inventario_obj.save()
return movimiento, inventario_obj
except Exception as e:
raise ValueError(f"Error al registrar movimiento y actualizar inventario: {str(e)}")
def registrar_movimiento(request):
"""
Vista para registrar un nuevo movimiento de inventario.
"""
if request.method == 'POST':
form = formilario_inventario(request.POST)
if form.is_valid():
movimiento_data = form.cleaned_data
try:
movimiento, inventario_obj = registrar_movimiento_y_actualizar_inventario(movimiento_data)
return redirect('registrar_movimiento') # Redirigir a una página de éxito
except ValueError as e:
return render(request, 'inventario_nuevo.html', {
'form': form,
'error': str(e)
})
else:
form = formilario_inventario()
return render(request, 'inventario_nuevo.html', {'form': form})
@login_required
def vista_inventario_mov(request):
persona = movimiento_inventario.objects.select_related('articulo','bodega','tipo_inventario').all()
return render(request,"mov_inventario_registro.html", {'persona':persona})

@ -0,0 +1,83 @@
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
import openpyxl
import csv
from django.template.loader import get_template
from xhtml2pdf import pisa
from django.shortcuts import render
from .models import inventario
@login_required
def generar_reporte_pdf(request):
# Obtener datos del inventario
inventarios = inventario.objects.all()
# Cargar la plantilla
template = get_template('pdf.html')
context = {'inventarios': inventarios}
# Renderizar la plantilla a HTML
html = template.render(context)
# Crear un objeto de respuesta PDF
response = HttpResponse(content_type='application/pdf')
response['Content-Disposition'] = 'inline; filename="reporte.pdf"'
# Convertir HTML a PDF
pisa_status = pisa.CreatePDF(html, dest=response)
if pisa_status.err:
return HttpResponse(f'Error al generar PDF: {pisa_status.err}', status=500)
return response
@login_required
def generar_reporte_excel(request):
# Crear un nuevo libro de Excel
wb = openpyxl.Workbook()
ws = wb.active
ws.title = 'Reporte de Inventario'
# Encabezados
headers = ['ID', 'Bodega', 'Artículo', 'Cantidad', 'Precio']
ws.append(headers)
# Datos del inventario
for item in inventario.objects.all():
ws.append([item.id, item.bodega.nombre_bodega, item.articulo.nombre_articulo, item.cantidad, item.precio])
# Configurar la respuesta HTTP
response = HttpResponse(content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename="reporte_inventario.xlsx"'
# Guardar el archivo en la respuesta
wb.save(response)
return response
@login_required
def generar_reporte_csv(request):
# Configurar la respuesta HTTP
response = HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="reporte_inventario.csv"'
writer = csv.writer(response)
# Encabezados
writer.writerow(['ID', 'Bodega', 'Artículo', 'Cantidad', 'Precio'])
# Datos del inventario
for item in inventario.objects.all():
writer.writerow([item.id, item.bodega.nombre_bodega, item.articulo.nombre_articulo, item.cantidad, item.precio])
return response
@login_required
def generar_grafico_chartjs(request):
inventarios = inventario.objects.all()
productos = [item.articulo.nombre_articulo for item in inventarios]
cantidades = [item.cantidad for item in inventarios]
return render(request, 'grafico_chartjs.html', {
'productos': productos,
'cantidades': cantidades,
})

@ -0,0 +1,2 @@
import pymysql
pymysql.install_as_MySQLdb()

@ -0,0 +1,16 @@
"""
ASGI config for TiendAlfa project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TiendAlfa.settings')
application = get_asgi_application()

@ -0,0 +1,132 @@
"""
Django settings for TiendAlfa project.
Generated by 'django-admin startproject' using Django 5.1.4.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
from pathlib import Path
# 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/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-f)f0@t_(a&ht0mo$&#nftao+_=s&^31u9))d=685^vs8&np=5k'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['store.stevz.dev','127.0.0.1']
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'Inventario',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'TiendAlfa.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'TiendAlfa.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # Motor de MySQL
'NAME': 'ttienda', # Nombre de la base de datos
'USER': 'ttienda', # Usuario de MySQL
'PASSWORD': 'Tienda$2024', # Contraseña de MySQL
'HOST': '10.138.214.232', # Dirección del servidor (por defecto localhost)
'PORT': '3306', # Puerto de MySQL (por defecto 3306)
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = 'static/'
LOGIN_URL= '/signin/'
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

@ -0,0 +1,54 @@
"""
URL configuration for TiendAlfa project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from Inventario import views, viewspdf
urlpatterns = [
path('admin/', admin.site.urls),
path('',views.generar_grafico_chartjs, name='home'),
path('logout/',views.signout, name ='logout'),
path('signin/',views.signin, name ='signin'),
path('proveedor/',views.proveedor_lista, name ='proveedor'),
path('proveedor/crear/',views.proveedor_registro, name ='proveedor_registro'),
path('proveedor/<int:task_id>/',views.Proveedor_update, name ='Proveedor_update'),
path('bodega/',views.bodega_vista, name ='bodega_vista'),
path('bodega/crearbodega/',views.bodega_registro, name ='bodega_registro'),
path('bodega/<int:task_id>/',views.bodega_update, name ='bodega_update'),
path('tipo/',views.tipo_vista, name ='tipo_vista'),
path('tipo/creartipo_articulo/',views.tipo_registro, name ='tipo_registro'),
path('tipo/<int:task_id>/',views.tipo_update, name ='tipo_update'),
path('articulo/',views.articulo_vista, name ='articulo_vista'),
path('articulo/crear/',views.articulo_registro, name ='articulo_registro'),
path('articulo/<int:task_id>/',views.articulo_update, name ='articulo_update'),
path('inventario/',views.inventario_vista, name ='inventario_vista'),
path('inventariomov/crear/',views.registrar_movimiento, name ='registrar_movimiento'),
path('inventariomov/',views.vista_inventario_mov, name ='vista_inventario_mov'),
path('reporte/pdf/',viewspdf.generar_reporte_pdf, name ='generar_reporte_pdf'),
path('reporte/excel/',viewspdf.generar_reporte_excel, name ='generar_reporte_excel'),
path('reporte/csv/',viewspdf.generar_reporte_csv, name ='generar_reporte_csv'),
path('grafico/chartjs/',viewspdf.generar_grafico_chartjs, name ='generar_grafico_chartjs'),
]

@ -0,0 +1,16 @@
"""
WSGI config for TiendAlfa project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TiendAlfa.settings')
application = get_wsgi_application()

@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'TiendAlfa.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
Loading…
Cancel
Save