first commit: sistema de gestión integral de inventarios

This commit is contained in:
Cap. Miguel Arcangel Ollarves Mayorquin 2026-06-02 15:05:33 -04:00
commit fd3f4fc1f3
5766 changed files with 2561629 additions and 0 deletions

88
README.md Normal file
View File

@ -0,0 +1,88 @@
# 📦 SISTEMA DE GESTIÓN DE INVENTARIO Y ENVÍO DE ARTÍCULOS
Sistema web desarrollado en **Django** para la gestión integral de inventarios de artículos (carpas, equipos, etc.), control de stock, asignación a unidades militares y generación de reportes PDF con comprobantes de envío.
---
## 📋 Tabla de Contenidos
- [📌 Características Principales](#-características-principales)
- [🛠️ Stack Tecnológico](#-stack-tecnológico)
- [🗃️ Modelos de Datos](#-modelos-de-datos)
- [📦 Requisitos Previos](#-requisitos-previos)
- [⚙️ Instalación y Configuración](#-instalación-y-configuración)
- [▶️ Ejecución del Servidor](#-ejecución-del-servidor)
- [📖 Uso del Sistema](#-uso-del-sistema)
- [🔐 Autenticación](#-autenticación)
- [📊 Módulos del Sistema](#-módulos-del-sistema)
- [📄 Generación de Reportes PDF](#-generación-de-reportes-pdf)
- [🔄 Flujo de Trabajo](#-flujo-de-trabajo)
- [🔒 Seguridad](#-seguridad)
- [🛠️ Mantenimiento](#-mantenimiento)
- [💡 Posibles Mejoras](#-posibles-mejoras)
- [📁 Estructura del Proyecto](#-estructura-del-proyecto)
---
## 📌 Características Principales
- ✅ Gestión completa de artículos (CRUD: Crear, Leer, Actualizar, Eliminar)
- ✅ Control de stock con actualización automática
- ✅ Gestión de unidades militares
- ✅ Envío de artículos a unidades con validación de stock
- ✅ Historial de movimientos por unidad
- ✅ Generación de comprobantes PDF de envío
- ✅ Reportes PDF por unidad con todos los artículos recibidos
- ✅ Autenticación de usuarios (login/logout)
- ✅ Interfaz responsive y amigable
- ✅ Eliminación masiva de comprobantes
---
## 🛠️ Stack Tecnológico
| Tecnología | Versión | Uso |
|------------|---------|-----|
| **Python** | 3.8+ | Lenguaje backend |
| **Django** | 5.0.4 | Framework web |
| **SQLite** | 3 | Base de datos (por defecto) |
| **xhtml2pdf** | Última | Generación de PDFs |
| **HTML5/CSS3** | - | Frontend |
| **Bootstrap** | 5 | Estilos y componentes |
| **Git** | - | Control de versiones |
---
## 🗃️ Modelos de Datos
| Modelo | Descripción | Campos principales |
|--------|-------------|-------------------|
| `Articulo` | Artículos del inventario | artículo, descripción, cantidad, fecha |
| `Unidad` | Unidades militares | nombreUnidad, comandante, ubicación, teléfono |
| `ArticuloUnidad` | Registro de envíos | movimiento, articulo, unidad, cantidad, fecha_salida |
| `PruebaUnidad` | Historial por unidad | movimiento, articulo, unidad, cantidad, fecha_salida |
### Relaciones
- `Unidad``Articulo`: Relación ManyToMany a través de `ArticuloUnidad`
- `PruebaUnidad`: Historial independiente para reportes por unidad
---
## 📦 Requisitos Previos
Antes de comenzar, asegúrate de tener instalado:
- **Python** 3.8 o superior
- **pip** (gestor de paquetes de Python)
- **Git** (opcional, para clonar el repositorio)
- **Virtualenv** (recomendado)
---
## ⚙️ Instalación y Configuración
### 1. Clonar el repositorio
```bash
git clone https://git.ejercito.mil.ve/maom/ProyectoTransporte.git
cd ProyectoTransporte

BIN
db.sqlite3 Normal file

Binary file not shown.

33036
get-pip.py Normal file

File diff suppressed because it is too large Load Diff

22
manage.py Normal file
View File

@ -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', 'sistema.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()

BIN
requirements.txt Normal file

Binary file not shown.

0
serving/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
serving/admin.py Normal file
View File

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

6
serving/apps.py Normal file
View File

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

21
serving/forms.py Normal file
View File

@ -0,0 +1,21 @@
from django import forms
from .models import Unidad, Articulo, ArticuloUnidad
class FormUnidad(forms.ModelForm):
class Meta:
model = Unidad
fields=['nombreUnidad', 'telefono', 'ubicacion', 'comandante']
class FormArticulo(forms.ModelForm):
class Meta:
model = Articulo
fields = ["articulo", "cantidad", "descripcion"]
class FormEnvio(forms.ModelForm):
cantidad = forms.IntegerField(required=True)
class Meta:
model = ArticuloUnidad
fields = ['articulo', 'cantidad' , 'unidad']

View File

@ -0,0 +1,64 @@
# Generated by Django 5.2.3 on 2025-07-01 14:49
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Articulo',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('articulo', models.TextField()),
('descripcion', models.TextField(null=True, verbose_name='Descripcion')),
('fecha', models.DateField(auto_now_add=True)),
('cantidad', models.IntegerField(default=0)),
],
),
migrations.CreateModel(
name='ArticuloUnidad',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('movimiento', models.CharField(max_length=200)),
('descripcion', models.TextField(null=True, verbose_name='Descripcion')),
('fecha_salida', models.DateField(auto_now_add=True)),
('cantidad', models.IntegerField(default=0)),
('articulo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='serving.articulo')),
],
),
migrations.CreateModel(
name='Unidad',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('nombreUnidad', models.CharField(max_length=200, verbose_name='Nombre de la Unidad')),
('comandante', models.CharField(max_length=200, verbose_name='Comandante')),
('ubicacion', models.TextField(null=True)),
('telefono', models.CharField(max_length=200, verbose_name='telefono')),
('articulos', models.ManyToManyField(through='serving.ArticuloUnidad', to='serving.articulo')),
],
),
migrations.CreateModel(
name='PruebaUnidad',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('movimiento', models.CharField(max_length=200)),
('descripcion', models.TextField(null=True, verbose_name='Descripcion')),
('fecha_salida', models.DateField(auto_now_add=True)),
('cantidad', models.IntegerField(default=0)),
('articulo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='serving.articulo')),
('unidad', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='serving.unidad')),
],
),
migrations.AddField(
model_name='articulounidad',
name='unidad',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='serving.unidad'),
),
]

View File

54
serving/models.py Normal file
View File

@ -0,0 +1,54 @@
from django.db import models
class Articulo(models.Model):
articulo = models.TextField()
descripcion = models.TextField(null=True, verbose_name="Descripcion")
fecha = models.DateField(auto_now_add=True)
cantidad = models.IntegerField(default=0)
def __str__(self):
return f"{self.articulo}-{self.descripcion}"
def total(self):
return self.cantidad
class Unidad(models.Model):
nombreUnidad = models.CharField(max_length=200, verbose_name="Nombre de la Unidad")
comandante = models.CharField(max_length=200, verbose_name="Comandante")
ubicacion = models.TextField(null=True)
telefono = models.CharField(max_length=200, verbose_name="telefono")
articulos = models.ManyToManyField(Articulo, through="ArticuloUnidad")
def __str__(self):
return f'{self.nombreUnidad} - {self.telefono}- {self.comandante}'
class ArticuloUnidad(models.Model):
movimiento = models.CharField(max_length=200)
descripcion = models.TextField(null=True, verbose_name="Descripcion")
articulo = models.ForeignKey(Articulo, on_delete=models.CASCADE)
unidad = models.ForeignKey(Unidad, on_delete=models.CASCADE)
fecha_salida = models.DateField(auto_now_add=True)
cantidad = models.IntegerField(default=0)
def __str__(self):
return f'{self.articulo}'
def total(self):
return self.cantidad
class PruebaUnidad(models.Model):
movimiento = models.CharField(max_length=200)
articulo = models.ForeignKey(Articulo, on_delete=models.CASCADE)
descripcion = models.TextField(null=True, verbose_name="Descripcion")
unidad = models.ForeignKey(Unidad, on_delete=models.CASCADE)
fecha_salida = models.DateField(auto_now_add=True)
cantidad = models.IntegerField(default=0)
def __str__(self):
return f"{self.articulo}"
def total(self):
return self.cantidad

View File

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Comprobante</title>
<style>
table {
overflow-x: auto;
border-collapse: collapse;
table-layout: fixed;
width: 50%;
}
table th,
td {
padding: 5px;
max-width: 400px;
word-wrap: break-word;
white-space: inherit;
}
table p {
text-align: center;
font-size: 10px;
font-weight: bold;
margin-bottom: 0px;
margin-top: 0px;
}
.bodertabla{
border: 1px solid black;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td colspan="5" style="padding: 10px; text-align:center;"><img src="{{img_uno}}" alt="icon" width="60" height="80"></td>
<td colspan="8">
<p style="margin-top: 0px;">REPÚPLICA BOLIVARIANA DE VENEZUELA</p>
<p style="margin-top: 0px;">MINISTERIO DEL PODER POPULAR PARA LA DEFENSA</p>
<p style="margin-top: 0px;">EJÉRCITO BOLIVARIANO</p>
<p style="margin-top: 0px;">SERVICIO DE INTENDENCIA</p>
</td>
<td colspan="5" style="padding: 20px;"><img src="{{img_dos}}" width="70"></td>
</tr>
</tbody>
<tbody>
<tr>
<td colspan="4" style="text-align:left;"></td>
<td colspan="5" style="text-align:center;"></td>
<td colspan="4" style="text-align:center;"></td>
<td colspan="4" style="text-align:right;">{{fecha|date:"d M Y"}}</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th colspan="18" style="padding: 10px;">
COMPROBANTE DE CARPAS
</th>
</tr>
</thead>
<thead>
<tr>
<th colspan="2" style="border: 1px solid black;"></th>
<th colspan="7" style="border: 1px solid black;">Carpa</th>
<th colspan="7" style="border: 1px solid black;">Descripcion</th>
<th colspan="2" style="border: 1px solid black;">Cantidad</th>
</tr>
</thead>
<tbody>
{% for articulos in articulos %}
<tr>
<td colspan="2" style="width: auto; text-align: center; border: 1px solid black;">{{forloop.counter}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.articulo.articulo}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.descripcion}}</td>
<td colspan="2" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.cantidad}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table>
<tbody>
<tr>
<td colspan="5" style="height: 150px;"></td>
<td colspan="5"></td>
<td colspan="5"></td>
</tr>
</tbody>
<thead>
<tr>
<th colspan="5" style="padding: 10px;">DIRECTOR</th>
<th colspan="5" style="padding: 10px;">ENTREGA</th>
<th colspan="5" style="padding: 10px;">RECIBE</th>
</tr>
</thead>
</table>
</body>
</html>

View File

@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block seccion %}
{% block titulodeseccion %} {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Crear Articulo{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title m-0">Registrar Carpas</h3>
</div>
</div>
<div class="card-body">
{% include 'articulos/formulario.html' %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,26 @@
{% extends 'base.html' %}
{% block seccion %}
{% block titulodeseccion %} {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Crear Articulo{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title m-0">Registrar Articulo</h3>
</div>
</div>
<div class="card-body">
{% include 'articulos/formulario.html' %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends 'base.html' %}
{% block contenido %}
<div class="col-lg-5">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3>Eliminar el Articulo Seleccionado</h3>
</div>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<p>¿Estás seguro de que quieres eliminar?</p>
<span>Se eliminara todos los datos de este articulo de la base de datos y no sera podran recuperar</span>
<h2>"{{ articulo.articulo }}"</h2>
{{ form }}
<input type="submit" value="Confirmar">
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,34 @@
<form action="" method="post">
{% csrf_token %}
<div class="form-group">
<label for="articulo">Carpas</label>
<textarea class="form-control" name="articulo" id="articulo" rows="3" placeholder="Articulo">{{form.articulo.value}}</textarea>
{% for error in formulario_articulo.errors.articulo %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group">
<label for="descripcion">Descripcion</label>
<textarea class="form-control" name="descripcion" id="descripcion" rows="3" placeholder="Descripcion">{{form.descripcion.value}}</textarea>
{% for error in formulario_articulo.errors.descripcion %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group">
<label for="cantidad">Cantidad</label>
<input type="number" class="form-control" name="cantidad" id="cantidad" value="{{form.cantidad.value}}" placeholder="Cantidad">
{% for error in formulario_articulo.errors.cantidad %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="d-flex justify-content-end card-outline mt-4">
<button type="submit" class="btn btn-dark">Guardar</button>
</div>
</form>

View File

@ -0,0 +1,102 @@
{% extends 'base.html' %}
{% block titulo %}Principal{% endblock %}
{% block seccion %}
{% block titulodeseccion %} Panel de Inventario {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Información{% endblock %}
{% endblock %}
{% block contenido %}
<!-- Small boxes (Stat box) -->
<div class="row">
<div class="col-lg-4 col-6">
<!-- small box -->
<div class="small-box bg-info">
<div class="inner">
<h3>{{ articulo|length }}</h3>
<p>ARTICULOS</p>
</div>
<div class="icon">
<i class="ion ion-bag"></i>
</div>
<a href="#" class="small-box-footer">Más información <i class="fas fa-arrow-circle-right"></i></a>
</div>
</div>
<!-- ./col -->
<div class="col-lg-4 col-6">
<!-- small box -->
<div class="small-box bg-success">
<div class="inner">
<h3>{{ unidades }}<sup style="font-size: 20px"></sup></h3>
<p>UNIDADES</p>
</div>
<div class="icon">
<i class="ion ion-stats-bars"></i>
</div>
<a href="{% url 'unidad' %}" class="small-box-footer">Más información <i class="fas fa-arrow-circle-right"></i></a>
</div>
</div>
<div class="col-lg-4 col-6">
<div class="small-box bg-warning">
<div class="inner">
<h3>{{ usuarios }}</h3>
<p>USUARIOS</p>
</div>
<div class="icon">
<i class="ion ion-person-add"></i>
</div>
<a href="#" class="small-box-footer">Más información <i class="fas fa-arrow-circle-right"></i></a>
</div>
</div>
<div class="col-lg-3 col-6">
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3></h3>
<!-- <a href="{% url 'envio_articulo' %}" class="btn btn-warning font-weight-bold"><i class="fas fa-solid fa-paper-plane"></i> Envio</a> -->
<a href="{% url 'crear_articulo' %}" class="btn btn-dark font-weight-bold"><i class="fas fa-solid fa-plus"></i> Agregar</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table id="example1" class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col" class="text-center"></th>
<th scope="col" class="text-center">Fecha Entrada</th>
<th scope="col" class="text-center">Carpas</th>
<th scope="col" class="text-center">Descripcion</th>
<th scope="col" class="text-center">Cantidad</th>
<th scope="col" class="text-center">Acciones</th>
</tr>
</thead>
<tbody>
{% for articulo in articulo %}
<tr class="">
<td class="text-center">{{forloop.counter}}</td>
<td class="text-center">{{articulo.fecha|date:"d-m-y"}}</td>
<td class="text-center">{{articulo.articulo}}</td>
<td class="text-center">{{articulo.descripcion}}</td>
<td class="text-center">{{articulo.cantidad}}</td>
<td class="text-center">
<a href="{% url 'editar' articulo.id %}" class="btn btn-info"><i class="fas fa-solid fa-pen"></i></a> |
<a href="{% url 'eliminar' articulo.id %}" class="btn btn-danger"><i class="fas fa-solid fa-trash"></i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

450
serving/templates/base.html Normal file
View File

@ -0,0 +1,450 @@
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{% block titulo %}{% endblock%}</title>
<!-- imagen Favicon -->
<link rel="icon" href="/static/imagenes/dos.ico" type="image/x-icon">
<!-- Google Font: Source Sans Pro -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback"/>
<!-- Ekko Lightbox -->
<link rel="stylesheet" href="/static/plugins/ekko-lightbox/ekko-lightbox.css"/>
<!-- SweetAlert2 -->
<link rel="stylesheet" href="/static/plugins/sweetalert2-theme-bootstrap-4/bootstrap-4.min.css">
<link rel="stylesheet" href="/static/plugins/toastr/toastr.min.css">
<!-- Font Awesome Icons -->
<link rel="stylesheet" href="/static/plugins/fontawesome-free/css/all.min.css"/>
<!-- IonIcons -->
<link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"/>
<!-- overlayScrollbars -->
<link rel="stylesheet" href="/static/plugins/overlayScrollbars/css/OverlayScrollbars.min.css" />
<!-- DataTables -->
<link rel="stylesheet" href="/static/plugins/datatables-bs4/css/dataTables.bootstrap4.min.css"/>
<link rel="stylesheet" href="/static/plugins/datatables-responsive/css/responsive.bootstrap4.min.css"/>
<link rel="stylesheet" href="/static/plugins/datatables-buttons/css/buttons.bootstrap4.min.css"/>
<!-- Select2 -->
<link rel="stylesheet" href="/static/plugins/select2/css/select2.min.css">
<link rel="stylesheet" href="/static/plugins/select2-bootstrap4-theme/select2-bootstrap4.min.css">
<!-- daterange picker -->
<link rel="stylesheet" href="/static/plugins/daterangepicker/daterangepicker.css">
<!-- iCheck for checkboxes and radio inputs -->
<link rel="stylesheet" href="/static/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
<!-- Bootstrap Color Picker -->
<link rel="stylesheet" href="/static/plugins/bootstrap-colorpicker/css/bootstrap-colorpicker.min.css">
<!-- Tempusdominus Bootstrap 4 -->
<link rel="stylesheet" href="/static/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css">
<!-- Bootstrap4 Duallistbox -->
<link rel="stylesheet" href="/static/plugins/bootstrap4-duallistbox/bootstrap-duallistbox.min.css">
<!-- BS Stepper -->
<link rel="stylesheet" href="/static/plugins/bs-stepper/css/bs-stepper.min.css">
<!-- dropzonejs -->
<link rel="stylesheet" href="/static/plugins/dropzone/min/dropzone.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="/static/bootstrap5/css/bootstrap.min.css" />
<link rel="stylesheet" href="/static/dist/css/adminlte.min.css" />
</head>
<body class="hold-transition sidebar-mini ayout-fixed layout-navbar-fixed layout-footer-fixed">
<div class="wrapper">
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#" role="button"
><i class="fas fa-bars"></i
></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="{% url 'articulos' %}" class="nav-link brand-text font-weight-bold">Inicio</a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="{% url 'unidad' %}" class="nav-link brand-text font-weight-bold">Unidad</a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="{% url 'envio_articulo' %}" class="nav-link brand-text font-weight-bold">Comprobante</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link" data-widget="navbar-search" href="#" role="button">
<i class="fas fa-search"></i>
</a>
<div class="navbar-search-block">
<form class="form-inline">
<div class="input-group input-group-sm">
<input class="form-control form-control-navbar" type="search" placeholder="Buscar" aria-label="Search"/>
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fas fa-search"></i>
</button>
<button class="btn btn-navbar" type="button" data-widget="navbar-search">
<i class="fas fa-times"></i>
</button>
</div>
</div>
</form>
</div>
</li>
<!-- Notifications Dropdown Menu -->
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#">
<img src="/static/dist/img/user2-160x160.jpg" class="img-circle elevation-1" alt="User Image" width="25px" height="25px"/>
<span class="brand-text font-weight-bold"> {{request.user.username}}</span>
</a>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
<span class="dropdown-item dropdown-header"
>Configuración</span>
<div class="dropdown-divider"></div>
<a href="{% url 'logout' %}" class="dropdown-item"><i class="fas fa-solid fa-power-off"></i> Salir <span class="float-right text-muted text-sm">3 mins</span>
</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" data-widget="fullscreen" href="#" role="button">
<i class="fas fa-expand-arrows-alt"></i>
</a>
</li>
<li class="nav-item"></li>
</ul>
</nav>
<!-- /.navbar -->
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<!-- Brand Logo -->
<a href="#" class="brand-link">
<img src="/static/imagenes/logo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3" style="opacity: 0.8"/>
<span class="brand-text font-weight-bold">SINTEJB</span>
</a>
<div class="sidebar">
<nav class="mt-2">
<ul
class="nav nav-pills nav-sidebar flex-column"
data-widget="treeview"
role="menu"
data-accordion="false"
></ul>
</nav>
</div>
</aside>
<div class="content-wrapper">
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0">{% block titulodeseccion %}{% endblock%}</h1>
</div>
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#"> {% block etiqueta1 %}{% endblock%}</a></li>
<li class="breadcrumb-item">{% block etiqueta2 %}{% endblock%}</li>
<li>{% block etiqueta3 %}{% endblock%}</li>
</ol>
</div>
</div>
</div>
</div>
<div class="content">
<div class="container-fluid">
{% block contenido %}{% endblock %}
</div>
</div>
</div>
<!-- Main Footer -->
<footer class="main-footer">
<strong>Copyright &copy; 2024-2030 <a href="#">Dirección de Teconologia de la Información y las Comunicaciones</a>.</strong>
<div class="float-right d-none d-sm-inline-block">
<b>Version</b> 0.0.1
</div>
</footer>
</div>
<!-- ./wrapper -->
<!-- REQUIRED SCRIPTS -->
<!-- jQuery -->
<script src="/static/plugins/jquery/jquery.min.js"></script>
<!-- Bootstrap -->
<script src="/static/bootstrap5/js/bootstrap.bundle.min.js"></script>
<script src="/static/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- overlayScrollbars -->
<script src="/static/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script>
<!-- AdminLTE -->
<script src="/static/dist/js/adminlte.js"></script>
<!-- Ekko Lightbox -->
<script src="/static/plugins/ekko-lightbox/ekko-lightbox.min.js"></script>
<!-- Filterizr-->
<script src="/static/plugins/filterizr/jquery.filterizr.min.js"></script>
<!-- OPTIONAL SCRIPTS -->
<script src="/static/plugins/chart.js/Chart.min.js"></script>
<!-- Select2 -->
<script src="/static/plugins/select2/js/select2.full.min.js"></script>
<!-- Bootstrap4 Duallistbox -->
<script src="/static/plugins/bootstrap4-duallistbox/jquery.bootstrap-duallistbox.min.js"></script>
<!-- InputMask -->
<script src="/static/plugins/moment/moment.min.js"></script>
<script src="/static/plugins/inputmask/jquery.inputmask.min.js"></script>
<!-- date-range-picker -->
<script src="/static/plugins/daterangepicker/daterangepicker.js"></script>
<!-- bootstrap color picker -->
<script src="/static/plugins/bootstrap-colorpicker/js/bootstrap-colorpicker.min.js"></script>
<!-- Tempusdominus Bootstrap 4 -->
<script src="/static/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
<!-- Bootstrap Switch -->
<script src="/static/plugins/bootstrap-switch/js/bootstrap-switch.min.js"></script>
<!-- BS-Stepper -->
<script src="/static/plugins/bs-stepper/js/bs-stepper.min.js"></script>
<!-- dropzonejs -->
<script src="/static/plugins/dropzone/min/dropzone.min.js"></script>
<!-- PAGE PLUGINS -->
<!-- jQuery Mapael -->
<script src="/static/plugins/jquery-mousewheel/jquery.mousewheel.js"></script>
<script src="/static/plugins/raphael/raphael.min.js"></script>
<script src="/static/plugins/jquery-mapael/jquery.mapael.min.js"></script>
<script src="/static/plugins/jquery-mapael/maps/usa_states.min.js"></script>
<!-- SweetAlert2 -->
<script src="/static/plugins/sweetalert2/sweetalert2.min.js"></script>
<!-- Toastr -->
<script src="/static/plugins/toastr/toastr.min.js"></script>
<!-- DataTables & Plugins -->
<script src="/static/plugins/datatables/jquery.dataTables.min.js"></script>
<script src="/static/plugins/datatables-bs4/js/dataTables.bootstrap4.min.js"></script>
<script src="/static/plugins/datatables-responsive/js/dataTables.responsive.min.js"></script>
<script src="/static/plugins/datatables-responsive/js/responsive.bootstrap4.min.js"></script>
<script src="/static/plugins/datatables-buttons/js/dataTables.buttons.min.js"></script>
<script src="/static/plugins/datatables-buttons/js/buttons.bootstrap4.min.js"></script>
<script src="/static/plugins/jszip/jszip.min.js"></script>
<script src="/static/plugins/pdfmake/pdfmake.min.js"></script>
<script src="/static/plugins/pdfmake/vfs_fonts.js"></script>
<script src="/static/plugins/datatables-buttons/js/buttons.html5.min.js"></script>
<script src="/static/plugins/datatables-buttons/js/buttons.print.min.js"></script>
<script src="/static/plugins/datatables-buttons/js/buttons.colVis.min.js"></script>
{% if messages %}
{% for message in messages %}
<script>
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
Toast.fire({
icon: "{{ message.tags }}",
title: "{{ message }}"
});
</script>
{% endfor %}
{% endif %}
</body>
</html>
<script>
$(function () {
$("#example1")
.DataTable({
responsive: true,
lengthChange: true,
autoWidth: false,
//buttons: ["copy", "csv", "excel", "pdf", "print", "colvis"],
language: {
"pageLength": "",
"decimal": "",
"emptyTable": "No hay datos",
"info": "Mostrando _START_ a _END_ de _TOTAL_ Registros",
"infoEmpty": "Mostrando 0 a 0 de 0 Registros",
"infoFiltered": "(Filtro de _MAX_ total Registros)",
"infoPostFix": "",
"thousands": ",",
"lengthMenu": "Mostrar _MENU_ Registros",
"loadingRecords": "Cargando...",
"processing": "Procesando...",
"search": "Buscar:",
"zeroRecords": "No se encontraron coincidencias",
"paginate": {
"first": "Primero",
"last": "Ultimo",
"next": "Próximo",
"previous": "Anterior",
},
"aria": {
"sortAscending": ": Activar orden de columna ascendente",
"sortDescending": ": Activar orden de columna desendente",
}
}
}).buttons().container().appendTo("#example1_wrapper .col-md-6:eq(0)");
$("#example2").DataTable({
paging: true,
lengthChange: false,
searching: false,
ordering: true,
info: true,
autoWidth: false,
responsive: true,
});
});
</script>
<script>
$(function () {
//Initialize Select2 Elements
$('.select2').select2()
//Initialize Select2 Elements
$('.select2bs4').select2({
theme: 'bootstrap4'
})
//Datemask dd/mm/yyyy
$('#datemask').inputmask('dd/mm/yyyy', { 'placeholder': 'dd/mm/yyyy' })
//Datemask2 mm/dd/yyyy
$('#datemask2').inputmask('mm/dd/yyyy', { 'placeholder': 'mm/dd/yyyy' })
//Money Euro
$('[data-mask]').inputmask()
//Date picker
$('#reservationdate').datetimepicker({
format: 'L'
});
//Date and time picker
$('#reservationdatetime').datetimepicker({ icons: { time: 'far fa-clock' } });
//Date range picker
$('#reservation').daterangepicker()
//Date range picker with time picker
$('#reservationtime').daterangepicker({
timePicker: true,
timePickerIncrement: 30,
locale: {
format: 'MM/DD/YYYY hh:mm A'
}
})
//Date range as a button
$('#daterange-btn').daterangepicker(
{
ranges : {
'Today' : [moment(), moment()],
'Yesterday' : [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'Last 7 Days' : [moment().subtract(6, 'days'), moment()],
'Last 30 Days': [moment().subtract(29, 'days'), moment()],
'This Month' : [moment().startOf('month'), moment().endOf('month')],
'Last Month' : [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
},
startDate: moment().subtract(29, 'days'),
endDate : moment()
},
function (start, end) {
$('#reportrange span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY'))
}
)
//Timepicker
$('#timepicker').datetimepicker({
format: 'LT'
})
//Bootstrap Duallistbox
$('.duallistbox').bootstrapDualListbox()
//Colorpicker
$('.my-colorpicker1').colorpicker()
//color picker with addon
$('.my-colorpicker2').colorpicker()
$('.my-colorpicker2').on('colorpickerChange', function(event) {
$('.my-colorpicker2 .fa-square').css('color', event.color.toString());
})
$("input[data-bootstrap-switch]").each(function(){
$(this).bootstrapSwitch('state', $(this).prop('checked'));
})
})
// BS-Stepper Init
document.addEventListener('DOMContentLoaded', function () {
window.stepper = new Stepper(document.querySelector('.bs-stepper'))
})
// DropzoneJS Demo Code Start
Dropzone.autoDiscover = false
// Get the template HTML and remove it from the doumenthe template HTML and remove it from the doument
var previewNode = document.querySelector("#template")
previewNode.id = ""
var previewTemplate = previewNode.parentNode.innerHTML
previewNode.parentNode.removeChild(previewNode)
var myDropzone = new Dropzone(document.body, { // Make the whole body a dropzone
url: "/target-url", // Set the url
thumbnailWidth: 80,
thumbnailHeight: 80,
parallelUploads: 20,
previewTemplate: previewTemplate,
autoQueue: false, // Make sure the files aren't queued until manually added
previewsContainer: "#previews", // Define the container to display the previews
clickable: ".fileinput-button" // Define the element that should be used as click trigger to select files.
})
myDropzone.on("addedfile", function(file) {
// Hookup the start button
file.previewElement.querySelector(".start").onclick = function() { myDropzone.enqueueFile(file) }
})
// Update the total progress bar
myDropzone.on("totaluploadprogress", function(progress) {
document.querySelector("#total-progress .progress-bar").style.width = progress + "%"
})
myDropzone.on("sending", function(file) {
// Show the total progress bar when upload starts
document.querySelector("#total-progress").style.opacity = "1"
// And disable the start button
file.previewElement.querySelector(".start").setAttribute("disabled", "disabled")
})
// Hide the total progress bar when nothing's uploading anymore
myDropzone.on("queuecomplete", function(progress) {
document.querySelector("#total-progress").style.opacity = "0"
})
// Setup the buttons for all transfers
// The "add files" button doesn't need to be setup because the config
// `clickable` has already been specified.
document.querySelector("#actions .start").onclick = function() {
myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED))
}
document.querySelector("#actions .cancel").onclick = function() {
myDropzone.removeAllFiles(true)
}
// DropzoneJS Demo Code End
</script>

View File

View File

@ -0,0 +1,67 @@
{% extends 'base.html' %}
{% block titulo %}Comprobante de Articulos{% endblock%}
{% block seccion %}
{% block titulodeseccion %} Comprobante de Articulos {%endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %}Formulario{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row justify-content-center">
<div class="col-lg-10">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title m-0">Comprobante de Articulos</h3>
</div>
</div>
<div class="card-body">
{% include 'envios/formulario.html' %}
<div class="table-responsive-xxl">
<table class="table">
<thead>
<tr>
<th scope="col" class="text-center"></th>
<th scope="col" class="text-center">Articulo</th>
<th scope="col" class="text-center">Cantidad</th>
</tr>
</thead>
<tbody>
{% if articulos_c %}
{% for comprobante in articulos_c %}
<tr>
<td class="text-center">{{forloop.counter}}</td>
<td class="text-center">{{comprobante.articulo.articulo}}</td>
<td class="text-center">{{comprobante.cantidad}}</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td colspan="6" class="text-center">No hay articulos</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
<div class="row">
<div class="col-12"><a href="{% url 'comprobante' %}" class="btn btn-dark float-left">Comprobante</a>
<form
method="post"
action="{% url 'borrar_todo' %}"
class="float-right"
>
{% csrf_token %}
<button type="submit" class="btn btn-danger">Elimina Todo</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,44 @@
<form action="" method="post">
{% csrf_token %}
<div class="row lign-items-center">
<div class="form-group col-md-3">
<label for="articulo_id">Articulo</label>
<select class="form-control" name="articulo" id="articulo_id" data-placeholder="Selecciona Articulos">
{% for articulo in articulo %}
<option value="{{articulo.id}}">{{forloop.counter}} - {{articulo.articulo}} - {{articulo.cantidad}}</option>
{% endfor %}
</select>
{% for error in formulario_envio.errors.articulo %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group col-md-3">
<label for="unidad_id">Unidad</label>
<select class="form-control" name="unidad" id="unidad_id">
{% for unidad in unidad %}
<option value="{{unidad.id}}"> {{forloop.counter}} - {{unidad.nombreUnidad}}</option>
{% endfor %}
</select>
{% for error in formulario_envio.errors.unidad %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group col-md-2">
<label for="cantidad"> Cantidad</label>
<input type="number" class="form-control" name="cantidad" id="cantidad">
{% for error in formulario_envio.errors.cantidad %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group col-md-4 d-flex align-items-center" style="padding-top: 30px;">
<button type="submit" class="btn btn-dark">+</button>
</div>
</div>
</form>

View File

@ -0,0 +1,76 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Acceso SINTGEJB </title>
<link rel="shortcut icon" type="image/png" href="/static/imagenes/icono.ico" />
<link rel="stylesheet" href="/static/plantilla1/src/assets/css/styles.min.css" />
</head>
<body>
<!-- Body Wrapper -->
<div class="page-wrapper" id="main-wrapper" data-layout="vertical" data-navbarbg="skin6" data-sidebartype="full"
data-sidebar-position="fixed" data-header-position="fixed">
<div
class="position-relative overflow-hidden radial-gradient min-vh-100 d-flex align-items-center justify-content-center">
<div class="d-flex align-items-center justify-content-center w-100">
<div class="row justify-content-center w-100">
<div class="col-md-8 col-lg-6 col-xxl-3">
<div class="card mb-0">
<div class="card-body">
<a href="./index.html" class="text-nowrap logo-img text-center d-block py-3 w-100">
<img src="/static/imagenes/logo.png" width="180" alt="">
</a>
<p class="text-center"> <b>Servicio de Intendencia del Ejército Bolivariano</b></p>
{% if form.errors %}
<p>Su nombre de usuario y contraseña no coinciden. Inténtalo de nuevo.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Su cuenta no tiene acceso a esta página. Para continuar, inicie sesión con una cuenta que tenga acceso.</p>
{% else %}
<p>Por favor inicie sesión para ver esta página.</p>
{% endif %}
{% endif %}
<form method="post" action="">
{% csrf_token %}
<div class="mb-3">
<label for="username" class="form-label">Nombre de usuario</label>
<input type="text" class="form-control" name="username" id="username" aria-describedby="emailHelp">
</div>
<div class="mb-4">
<label for="password" class="form-label">Contraseña</label>
<input type="password" class="form-control" name="password" id="password">
</div>
<div class="d-flex align-items-center justify-content-between mb-3">
<div class="form-check">
<input class="form-check-input primary" type="checkbox" value="" id="flexCheckChecked" checked>
<label class="form-check-label text-dark" for="flexCheckChecked">
Recuerda
</label>
</div>
<a class="text-primary fw-bold" href="{% url 'password_reset' %}">Has olvidado tu contraseña?</a>
</div>
<input type="submit" class="btn btn-primary w-100 fs-4 mb-4 rounded-2" value="Iniciar sesión">
<div class="d-flex align-items-center justify-content-center">
<!-- <p class="fs-4 mb-0 fw-bold">Eres Nuevo</p>
<a class="text-primary fw-bold ms-2" href="./authentication-register.html">Crea una cuenta</a> -->
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="/static/plantilla1/src/assets/libs/jquery/dist/jquery.min.js"></script>
<script src="/static/plantilla1/src/assets/libs/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Comprobante</title>
<style>
table {
overflow-x: auto;
border-collapse: collapse;
table-layout: fixed;
width: 50%;
}
table th,
td {
padding: 5px;
max-width: 400px;
word-wrap: break-word;
white-space: inherit;
}
table p {
text-align: center;
font-size: 10px;
font-weight: bold;
margin-bottom: 0px;
margin-top: 0px;
}
.bodertabla {
border: 1px solid black;
}
</style>
</head>
<body>
<table>
<tbody>
<tr>
<td colspan="5" style="padding: 10px; text-align:center;"><img src="{{img_uno}}" alt="icon" width="60"
height="80"></td>
<td colspan="8">
<p style="margin-top: 0px;">REPÚPLICA BOLIVARIANA DE VENEZUELA</p>
<p style="margin-top: 0px;">MINISTERIO DEL PODER POPULAR PARA LA DEFENSA</p>
<p style="margin-top: 0px;">EJÉRCITO BOLIVARIANO</p>
<p style="margin-top: 0px;">SERVICIO DE INTENDENCIA</p>
</td>
<td colspan="5" style="padding: 20px;"><img src="{{img_dos}}" width="70"></td>
</tr>
</tbody>
<tbody>
<tr>
<td colspan="4" style="text-align:left;"></td>
<td colspan="5" style="text-align:center;"></td>
<td colspan="4" style="text-align:center;"></td>
<td colspan="4" style="text-align:right;">{{fecha|date:"d M Y"}}</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th colspan="30" style="padding: 10px;">
Hitorial del Material Enviado o Recibido
</th>
</tr>
</thead>
<thead>
<tr>
<th colspan="2" style="border: 1px solid black;"></th>
<th colspan="7" style="border: 1px solid black;">Fecha</th>
<th colspan="7" style="border: 1px solid black;">Movimiento</th>
<th colspan="7" style="border: 1px solid black;">Carpa</th>
<th colspan="7" style="border: 1px solid black;">Descripcion</th>
<th colspan="2" style="border: 1px solid black;">Cant</th>
</tr>
</thead>
<tbody>
{% for articulos in articulos %}
<tr>
<td colspan="2" style="width: auto; text-align: center; border: 1px solid black;">{{forloop.counter}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.fecha_salida}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.movimiento}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.articulo.articulo}}</td>
<td colspan="7" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.descripcion}}</td>
<td colspan="2" style="width: auto; text-align: center; border: 1px solid black;">{{articulos.cantidad}}</td>
</tr>
{% endfor %}
</tbody>
</table>
<table>
<tbody>
<tr>
<td colspan="5" style="height: 150px;"></td>
<td colspan="5"></td>
<td colspan="5"></td>
</tr>
</tbody>
<thead>
<tr>
<th colspan="5" style="padding: 10px;">DIRECTOR</th>
<th colspan="5" style="padding: 10px;">ENTREGA</th>
<th colspan="5" style="padding: 10px;">RECIBE</th>
</tr>
</thead>
</table>
</body>
</html>

View File

@ -0,0 +1,57 @@
{% extends 'base.html' %}
{% block titulo %}Articulo Recibidos{% endblock %}
{% block seccion %}
{% block titulodeseccion %} Historial de Carpas {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Información{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row">
<div class="col-lg-12">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h1> <a href="{% url 'lista' unidad.id %}">Imprimir Historial</a></h1>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table id="example1" class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col"></th>
<th scope="col">Articulo</th>
<th scope="col">Movimiento</th>
<th scope="col">Fecha Entrada</th>
<th scope="col">Descripcion</th>
<th scope="col">Cantidad</th>
</tr>
</thead>
<tbody>
{% for objetos in articulo %}
<tr class="">
<td>{{forloop.counter}}</td>
<td>{{objetos.articulo.articulo}}</td>
<td>{{objetos.movimiento}}</td>
<td>{{objetos.fecha_salida|date:"d-m-y"}}</td>
<td>{{objetos.descripcion}}</td>
<td>{{objetos.cantidad}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,29 @@
{% extends 'base.html' %}
{% block seccion %}
{% block titulodeseccion %} Unidad Registro {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Registro de Unidad{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title m-0">Unidad</h3>
</div>
</div>
<div class="card-body">
{% include 'unidad/formulario_unidad.html' %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,28 @@
{% extends 'base.html' %}
{% block seccion %}
{% block titulodeseccion %} Unidad Registro {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Registro de Unidad{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row justify-content-center">
<div class="col-lg-6">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3 class="card-title m-0">Unidad</h3>
</div>
</div>
<div class="card-body">
{% include 'unidad/formulario_unidad.html' %}
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,27 @@
{% extends 'base.html' %}
{% block contenido %}
<div class="col-lg-5">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3>Eliminar el Articulo Seleccionado</h3>
</div>
</div>
<div class="card-body">
<form method="post">
{% csrf_token %}
<p>¿Estás seguro de que quieres eliminar? </p>
<span>se eliminaran todos los datos de esta unidad registrada y no podra recuperar la información</span>
<h3>"{{ unidad.nombreUnidad }}"</h3>
{{ form }}
<input type="submit" value="Confirmar">
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,41 @@
<form action="" method="post">
{% csrf_token %}
<div class="form-group">
<label for="nombreUnidad">Identificación de la Unidad</label>
<input type="text" class="form-control" name="nombreUnidad" id="nombreUnidad" value="{{form.nombreUnidad.value}}" placeholder="Nombre de la Unidad">
{% for error in formulario_unidad.errors.nombreUnidad %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group">
<label for="comandante">Comandante</label>
<input type="text" class="form-control" name="comandante" id="comandante" value="{{form.comandante.value}}" placeholder="Nombre del Comandante">
{% for error in formulario_unidad.errors.comandante %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group">
<label for="telefono">Telefono</label>
<input type="tel" class="form-control" name="telefono" id="telefono" value="{{form.telefono.value}}" placeholder="Telefono">
{% for error in formulario_unidad.errors.telefono %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="form-group">
<label for="ubicacion">Ubicacion</label>
<textarea class="form-control" name="ubicacion" id="ubicacion" rows="3" placeholder="Ubicacion...">{{form.ubicacion.value}}</textarea>
{% for error in formulario_unidad.errors.ubicacion %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
<div class="d-flex justify-content-end card-outline mt-4">
<button type="submit" class="btn btn-dark">Guardar</button>
</div>
</form>

View File

@ -0,0 +1,67 @@
{% extends 'base.html' %}
{% block titulo %}
Unidad
{% endblock %}
{% block seccion %}
{% block titulodeseccion %} Unidad {% endblock%}
{% block etiqueta1 %}Inicio{% endblock %}
{% block etiqueta2 %} Información{% endblock %}
{% endblock %}
{% block contenido %}
<div class="row">
<div class="col-lg-12">
<div class="card card-dark card-outline">
<div class="card-header">
<div class="d-flex justify-content-between">
<h3></h3>
<a href="{% url 'crear_unidad' %}" class="btn btn-dark font-weight-bold"><i class="fas fa-solid fa-plus"></i> Agregar</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table id="example1" class="table align-items-center table-flush">
<thead class="thead-light">
<tr>
<th scope="col"></th>
<th scope="col">Nombre de la Unidad</th>
<th scope="col">Comandante</th>
<th scope="col">Telefono</th>
<th scope="col">Ubicación</th>
<th scope="col">Acciones</th>
</tr>
</thead>
<tbody>
{% for unidad in unidad %}
<tr class="">
<td>{{forloop.counter}}</td>
<td>{{unidad.nombreUnidad}}</td>
<td>{{unidad.comandante}}</td>
<td>{{unidad.telefono}}</td>
<td>{{unidad.ubicacion}}</td>
<td>
<a href="{% url 'unidad_articulo' unidad.id %}" class="btn btn-dark"><i class="fas fa-solid fa-eye"></i></a> |
<a href="{% url 'editar_unidad' unidad.id %}" class="btn btn-info"><i class="fas fa-solid fa-pen"></i></a> |
<a href="{% url 'eliminar_unidad' unidad.id %}" class="btn btn-danger"><i class="fas fa-solid fa-trash"></i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

3
serving/tests.py Normal file
View File

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

58
serving/urls.py Normal file
View File

@ -0,0 +1,58 @@
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from serving.views import (
VistaInventario,
CrearArticulo,
VistaEnvio,
VistaUnidad,
CrearUnidad,
UnidadArticulo,
EditarVista,
EliminarVista,
EditarVistaUnidad,
EliminarVistaUnidad,
ComprobanteVista,
BorrarVistaComprobante,
AccesoVista,
CerrarVista,
ListaVista,
)
urlpatterns = [
path("", VistaInventario.as_view(), name="articulos"),
path("articulos/crear.html", CrearArticulo.as_view(), name="crear_articulo"),
path("articulos/editar/<int:pk>", EditarVista.as_view(), name="editar"),
path("articulos/<int:pk>/eliminar/", EliminarVista.as_view(), name="eliminar"),
# envios
path("envios/envio_articulo", VistaEnvio.as_view(), name="envio_articulo"),
# Unidad
path("unidad/unidad_index", VistaUnidad.as_view(), name="unidad"),
path("unidad/crear_unidad", CrearUnidad.as_view(), name="crear_unidad"),
path(
"unidad/editar_unidad/<int:pk>",
EditarVistaUnidad.as_view(),
name="editar_unidad",
),
path(
"unidad/<int:pk>/eliminar_unidad/",
EliminarVistaUnidad.as_view(),
name="eliminar_unidad",
),
# subunidades
path(
"subunidad/unidad_articulo/<int:id>",
UnidadArticulo.as_view(),
name="unidad_articulo",
),
# comprobantes PDF
path("articulos/comprobante/", ComprobanteVista.as_view(), name="comprobante"),
path("subunidad/lista/<int:id>", ListaVista.as_view(), name="lista"),
# eliminacion de todo lo del comprobante
path("envios/borrartodo", BorrarVistaComprobante.as_view(), name="borrar_todo"),
# acceso vista
path("registration/login/", AccesoVista.as_view(), name="login"),
path("accounts/logout/", CerrarVista.as_view(), name="logout"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

276
serving/views.py Normal file
View File

@ -0,0 +1,276 @@
from django.shortcuts import render, redirect
from django.urls import reverse_lazy
from django.views import View
from datetime import datetime
from django.contrib import messages
from django.contrib.auth.views import LogoutView, LoginView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.contrib.auth import logout
from django.conf import settings
from django.http import HttpRequest, HttpResponse, QueryDict, HttpResponseRedirect
from django.template.loader import get_template
from xhtml2pdf import pisa
from django.contrib.staticfiles import finders
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic import RedirectView
from django.db.models import Sum
from django.contrib.auth.models import User
from .models import Unidad, Articulo, ArticuloUnidad, PruebaUnidad
from .forms import FormUnidad , FormArticulo, FormEnvio
# vista de inventario
class VistaInventario(LoginRequiredMixin,View):
def get(self, request, *args, **kwargs):
articulo = Articulo.objects.all()
unidades = Unidad.objects.all().count()
usuarios = User.objects.all().count()
context = {'articulo':articulo, 'unidades':unidades, 'usuarios':usuarios}
return render(request, 'articulos/index.html', context)
class CrearArticulo(LoginRequiredMixin, CreateView):
form_class = FormArticulo
initial = {"key": "value"}
template_name = "articulos/crear.html"
def get(self, request, *args, **kwargs):
formulario_articulo = self.form_class(initial=self.initial)
context = {'formulario_articulo':formulario_articulo}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
formulario_articulo =self.form_class(request.POST)
if formulario_articulo.is_valid():
formulario_articulo.save()
messages.success(request,'Se registro Carpas con Exito')
return redirect('articulos')
return render(request, self.template_name, {'formulario_articulo':formulario_articulo})
class EditarVista(LoginRequiredMixin, UpdateView):
model = Articulo
form_class = FormArticulo
template_name = "articulos/editar.html"
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, self.template_name, *args, **kwargs)
def get_initial(self):
initial = super().get_initial()
# initial['serial'] = self.object.serial
return initial
def form_valid(self, form):
if form.is_valid():
self.object = form.save()
return redirect('articulos')
else:
return render(self.template_name, {'form': form})
class EliminarVista(LoginRequiredMixin, DeleteView):
model = Articulo
template_name = "articulos/eliminar.html"
success_url = reverse_lazy('articulos')
class ComprobanteVista(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
try:
articulos = ArticuloUnidad.objects.all()
fecha = datetime.now().date()
img_uno = settings.STATIC_ROOT + '/imagenes/imagen.png'
img_dos = settings.STATIC_ROOT + '/imagenes/logo.png'
template_path = "articulos/comprobante.html"
context = {
"articulos": articulos,
"fecha": fecha,
"img_uno": img_uno,
"img_dos": img_dos,
}
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = (
'attachment; filename="comprobantes.pdf"'
)
template = get_template(template_path)
html = template.render(context)
pisa_status = pisa.CreatePDF(html, dest=response)
if pisa_status.err:
return HttpResponse("We had some errors <pre>" + html + "</pre>")
return response
except:
return render(request, "articulos/comprobante.html")
# ---------- fin de la vista inventario
# inicio de la vista de envio de articulos
class VistaEnvio(LoginRequiredMixin, CreateView):
form_class = FormEnvio
initial = {"key": "value"}
template_name = "envios/envio_articulo.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["formulario_envio"] = self.get_form()
return context
def get(self, request, *args, **kwargs):
articulo = Articulo.objects.all()
articulos_c = ArticuloUnidad.objects.all()
unidad = Unidad.objects.all()
context = {"articulo": articulo, "unidad": unidad, "articulos_c": articulos_c}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
formulario_envio = self.form_class(request.POST)
# Verifica si el formulario es válido
if formulario_envio.is_valid():
unidad = formulario_envio.cleaned_data["unidad"]
cantidad = formulario_envio.cleaned_data["cantidad"]
articulo = formulario_envio.cleaned_data["articulo"]
if articulo.cantidad < cantidad:
messages.error(request, "No hay suficientes artículos en stock.")
return redirect("envio_articulo")
# Proceder con el envío si hay suficientes artículos
articulo.cantidad -= cantidad
articulo.save()
ArticuloUnidad.objects.create(
movimiento="ENVIADO",
articulo=articulo,
unidad=unidad,
cantidad=cantidad,
descripcion=articulo.descripcion,
)
PruebaUnidad.objects.create(
movimiento="RECIBIDO",
articulo=articulo,
unidad=unidad,
cantidad=cantidad,
descripcion=articulo.descripcion,
)
messages.success(request,"Se registro con exito.")
return redirect("envio_articulo")
else:
messages.error(request,"rellene los campos")
return redirect('envio_articulo')
# fin de la vista de envio de articulos
class BorrarVistaComprobante(LoginRequiredMixin, View):
template_name = "envios/borrartodo.html"
success_url = reverse_lazy("envio_articulo")
def get(self, request):
return render(request, self.template_name)
def post(self, request):
ArticuloUnidad.objects.all().delete()
messages.success(request,'se elimino todo')
return HttpResponseRedirect(self.success_url)
# fin de la vista de articulos
class VistaUnidad(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
unidad = Unidad.objects.all()
context = {'unidad':unidad}
return render(request, 'unidad/unidad_index.html',context)
class CrearUnidad(LoginRequiredMixin, CreateView):
form_class = FormUnidad
initial = {"key": "value"}
template_name = "unidad/crear_unidad.html"
def get(self, request, *args, **kwargs):
formulario_unidad = self.form_class(initial=self.initial)
context = {'formulario_unidad':formulario_unidad}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
formulario_unidad = self.form_class(request.POST)
if formulario_unidad.is_valid():
formulario_unidad.save()
return redirect('unidad')
return render(request, self.template_name, {'formulario_unidad':formulario_unidad})
class UnidadArticulo(LoginRequiredMixin, View):
def get(self, request, id):
unidad= Unidad.objects.get(pk=id)
articulo = PruebaUnidad.objects.filter(unidad=unidad)
context={'articulo':articulo, 'unidad':unidad}
return render(request, 'subunidad/unidad_articulo.html',context)
class EditarVistaUnidad(LoginRequiredMixin, UpdateView):
model = Unidad
form_class = FormUnidad
template_name = "unidad/editar_unidad.html"
def get(self, request, *args, **kwargs):
self.object = self.get_object()
return super().get(request, self.template_name, *args, **kwargs)
def get_initial(self):
initial = super().get_initial()
return initial
def form_valid(self, form):
self.object = form.save()
return redirect('unidad')
class EliminarVistaUnidad(LoginRequiredMixin, DeleteView):
model = Unidad
template_name = "unidad/eliminar_unidad.html"
success_url = reverse_lazy('unidad')
class ListaVista(LoginRequiredMixin, View):
def get(self, request, id, *args, **kwargs):
try:
unidad = Unidad.objects.get(pk=id)
articulos = PruebaUnidad.objects.filter(unidad=id)
fecha = datetime.now().date()
img_uno = settings.STATIC_ROOT + "/imagenes/imagen.png"
img_dos = settings.STATIC_ROOT + "/imagenes/logo.png"
template_path = "subunidad/lista.html"
context = {
"articulos": articulos,
"fecha": fecha,
"img_uno": img_uno,
"img_dos": img_dos,
}
response = HttpResponse(content_type="application/pdf")
response["Content-Disposition"] = 'attachment; filename="comprobantes.pdf"'
template = get_template(template_path)
html = template.render(context)
pisa_status = pisa.CreatePDF(html, dest=response)
if pisa_status.err:
return HttpResponse("We had some errors <pre>" + html + "</pre>")
return response
except:
return render(request, "subunidad/lista.html")
class AccesoVista(LoginView):
login_url = "registration/login.html"
redirect_field_name = "redirect_to"
class CerrarVista(RedirectView):
def get(self, request):
logout(request)
return redirect("login")

0
sistema/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

16
sistema/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for sistema 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.0/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sistema.settings')
application = get_asgi_application()

140
sistema/settings.py Normal file
View File

@ -0,0 +1,140 @@
"""
Django settings for sistema project.
Generated by 'django-admin startproject' using Django 5.0.4.
For more information on this file, see
https://docs.djangoproject.com/en/5.0/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.0/ref/settings/
"""
from pathlib import Path
import os
# 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.0/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-e^u3__^x9+5*5-1%_3@dbx)h-=om)w(yt8l#q^a@=b1xjtn@n$'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = ['*']
# Application definition
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"serving",
"xhtml2pdf",
]
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 = 'sistema.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 = 'sistema.wsgi.application'
# Database
# https://docs.djangoproject.com/en/5.0/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3', # BASE_DIR es la ruta al directorio base de tu proyecto
},
}
# Password validation
# https://docs.djangoproject.com/en/5.0/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.0/topics/i18n/
LANGUAGE_CODE = 'es'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.0/howto/static-files/
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
STATICFILES_DIRS = [os.path.join(BASE_DIR, "static")]
MEDIA_URL = '/imagenes/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
LOGIN_REDIRECT_URL = "/"
SESSION_EXPIRE_SECONDS = 200 # Expire después de 5 minutos
SESSION_EXPIRE_AFTER_LAST_ACTIVITY = True
# Default primary key field type
# https://docs.djangoproject.com/en/5.0/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

25
sistema/urls.py Normal file
View File

@ -0,0 +1,25 @@
"""
URL configuration for sistema project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.0/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 include, path
urlpatterns = [
path("", include("serving.urls")),
path("admin/", admin.site.urls),
path("accounts/", include("django.contrib.auth.urls")),
]

16
sistema/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for sistema 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.0/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sistema.settings')
application = get_wsgi_application()

5002
static/bootstrap5/css/bootstrap-grid.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,426 @@
/*!
* Bootstrap Reboot v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
background-color: #fff;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr /* rtl:ignore */;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.min.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,423 @@
/*!
* Bootstrap Reboot v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #212529;
background-color: #fff;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
background-color: currentColor;
border: 0;
opacity: 0.25;
}
hr:not([size]) {
height: 1px;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title],
abbr[data-bs-original-title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.2em;
background-color: #fcf8e3;
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: #0d6efd;
text-decoration: underline;
}
a:hover {
color: #0a58ca;
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-size: 1em;
direction: ltr ;
unicode-bidi: bidi-override;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: #d63384;
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.2rem 0.4rem;
font-size: 0.875em;
color: #fff;
background-color: #212529;
border-radius: 0.2rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
font-weight: 700;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: #6c757d;
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]::-webkit-calendar-picker-indicator {
display: none;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
outline-offset: -2px;
-webkit-appearance: textfield;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::file-selector-button {
font: inherit;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,8 @@
/*!
* Bootstrap Reboot v5.0.2 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors
* Copyright 2011-2021 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
* Forked from Normalize.css, licensed MIT (https://github.com/necolas/normalize.css/blob/master/LICENSE.md)
*/*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";font-size:1rem;font-weight:400;line-height:1.5;color:#212529;background-color:#fff;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:500;line-height:1.2}h1{font-size:calc(1.375rem + 1.5vw)}@media (min-width:1200px){h1{font-size:2.5rem}}h2{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){h2{font-size:2rem}}h3{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){h3{font-size:1.75rem}}h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){h4{font-size:1.5rem}}h5{font-size:1.25rem}h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[data-bs-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-right:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-right:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}small{font-size:.875em}mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#0d6efd;text-decoration:underline}a:hover{color:#0a58ca}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;font-size:1em;direction:ltr;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:#d63384;word-wrap:break-word}a>code{color:inherit}kbd{padding:.2rem .4rem;font-size:.875em;color:#fff;background-color:#212529;border-radius:.2rem}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:right}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:right;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:right}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}[type=email],[type=number],[type=tel],[type=url]{direction:ltr}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}
/*# sourceMappingURL=bootstrap-reboot.rtl.min.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10837
static/bootstrap5/css/bootstrap.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

10813
static/bootstrap5/css/bootstrap.rtl.css vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More