Initial commit - estructura completa del proyecto
This commit is contained in:
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.env
|
||||||
|
*.log
|
||||||
|
__pycache__/
|
||||||
|
venv/
|
||||||
|
node_modules/
|
||||||
|
vendor/
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
21
backend/Dockerfile
Normal file
21
backend/Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Instalar dependencias del sistema
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
gcc \
|
||||||
|
libpq-dev \
|
||||||
|
postgresql-client \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Copiar requirements e instalar dependencias Python
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
# Copiar el proyecto
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
CMD ["sh", "-c", "sleep 5 && python manage.py migrate && python manage.py runserver 0.0.0.0:8000"]
|
||||||
0
backend/inventario/__init__.py
Normal file
0
backend/inventario/__init__.py
Normal file
3
backend/inventario/admin.py
Normal file
3
backend/inventario/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
backend/inventario/apps.py
Normal file
6
backend/inventario/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class InventarioConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'inventario'
|
||||||
0
backend/inventario/migrations/__init__.py
Normal file
0
backend/inventario/migrations/__init__.py
Normal file
3
backend/inventario/models.py
Normal file
3
backend/inventario/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
backend/inventario/tests.py
Normal file
3
backend/inventario/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
backend/inventario/views.py
Normal file
3
backend/inventario/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
22
backend/manage.py
Executable file
22
backend/manage.py
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pycore_db.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()
|
||||||
0
backend/pycore/__init__.py
Normal file
0
backend/pycore/__init__.py
Normal file
16
backend/pycore/asgi.py
Normal file
16
backend/pycore/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for pycore 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/4.2/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pycore_db.settings')
|
||||||
|
|
||||||
|
application = get_asgi_application()
|
||||||
102
backend/pycore/settings.py
Normal file
102
backend/pycore/settings.py
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import sys
|
||||||
|
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
SECRET_KEY = os.environ.get('SECRET_KEY', 'clave-temporal-cambiar')
|
||||||
|
|
||||||
|
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'backend', '0.0.0.0']
|
||||||
|
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'rest_framework',
|
||||||
|
'corsheaders',
|
||||||
|
'inventario',
|
||||||
|
'ventas',
|
||||||
|
'sucursales',
|
||||||
|
]
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'corsheaders.middleware.CorsMiddleware',
|
||||||
|
'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 = 'pycore.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 = 'pycore.wsgi.application'
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.postgresql',
|
||||||
|
'NAME': 'pycore_db',
|
||||||
|
'USER': 'Scorpion',
|
||||||
|
'PASSWORD': 'CyCoT256',
|
||||||
|
'HOST': 'db',
|
||||||
|
'PORT': '5432',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
LANGUAGE_CODE = 'es-mx'
|
||||||
|
TIME_ZONE = 'America/Mexico_City'
|
||||||
|
USE_I18N = True
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
REST_FRAMEWORK = {
|
||||||
|
'DEFAULT_PERMISSION_CLASSES': [
|
||||||
|
'rest_framework.permissions.AllowAny',
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
CORS_ALLOW_ALL_ORIGINS = True
|
||||||
22
backend/pycore/urls.py
Normal file
22
backend/pycore/urls.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for pycore project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/4.2/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
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
]
|
||||||
16
backend/pycore/wsgi.py
Normal file
16
backend/pycore/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for pycore 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/4.2/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pycore.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
7
backend/requirements.txt
Normal file
7
backend/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Django==4.2.7
|
||||||
|
djangorestframework==3.14.0
|
||||||
|
django-cors-headers==4.3.1
|
||||||
|
psycopg2-binary==2.9.7
|
||||||
|
python-decouple==3.8
|
||||||
|
Pillow==10.0.1
|
||||||
|
gunicorn==21.2.0
|
||||||
0
backend/sucursales/__init__.py
Normal file
0
backend/sucursales/__init__.py
Normal file
3
backend/sucursales/admin.py
Normal file
3
backend/sucursales/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
backend/sucursales/apps.py
Normal file
6
backend/sucursales/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SucursalesConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'sucursales'
|
||||||
0
backend/sucursales/migrations/__init__.py
Normal file
0
backend/sucursales/migrations/__init__.py
Normal file
3
backend/sucursales/models.py
Normal file
3
backend/sucursales/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
backend/sucursales/tests.py
Normal file
3
backend/sucursales/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
backend/sucursales/views.py
Normal file
3
backend/sucursales/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
0
backend/ventas/__init__.py
Normal file
0
backend/ventas/__init__.py
Normal file
3
backend/ventas/admin.py
Normal file
3
backend/ventas/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
backend/ventas/apps.py
Normal file
6
backend/ventas/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class VentasConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'ventas'
|
||||||
0
backend/ventas/migrations/__init__.py
Normal file
0
backend/ventas/migrations/__init__.py
Normal file
3
backend/ventas/models.py
Normal file
3
backend/ventas/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
backend/ventas/tests.py
Normal file
3
backend/ventas/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
3
backend/ventas/views.py
Normal file
3
backend/ventas/views.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
# Create your views here.
|
||||||
16
backend/wait-for-db.sh
Executable file
16
backend/wait-for-db.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# wait-for-db.sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
host="$1"
|
||||||
|
shift
|
||||||
|
cmd="$@"
|
||||||
|
|
||||||
|
until PGPASSWORD=$POSTGRES_PASSWORD psql -h "$host" -U "Scorpion" -d "pycore_db" -c '\q'; do
|
||||||
|
>&2 echo "PostgreSQL no está disponible - esperando..."
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
>&2 echo "PostgreSQL está listo - ejecutando comando"
|
||||||
|
exec $cmd
|
||||||
48
check-status.sh
Executable file
48
check-status.sh
Executable file
@@ -0,0 +1,48 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🔍 Verificando estado de pycore ..."
|
||||||
|
|
||||||
|
echo "📊 Contenedores:"
|
||||||
|
docker-compose ps
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "🌐 Verificando servicios:"
|
||||||
|
|
||||||
|
# Esperar un poco para que todo esté listo
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
# Verificar backend
|
||||||
|
echo -n "Backend (8000): "
|
||||||
|
if curl -s http://localhost:8000 > /dev/null; then
|
||||||
|
echo "✅ OK"
|
||||||
|
else
|
||||||
|
echo "❌ Falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar frontend
|
||||||
|
echo -n "Frontend (3000): "
|
||||||
|
if curl -s http://localhost:3000 > /dev/null; then
|
||||||
|
echo "✅ OK"
|
||||||
|
else
|
||||||
|
echo "❌ Falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar pgadmin
|
||||||
|
echo -n "PgAdmin (5050): "
|
||||||
|
if curl -s http://localhost:5050 > /dev/null; then
|
||||||
|
echo "✅ OK"
|
||||||
|
else
|
||||||
|
echo "❌ Falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Verificar base de datos
|
||||||
|
echo -n "Base de datos: "
|
||||||
|
if docker-compose exec db pg_isready -U Scorpion -d pycore_db; then
|
||||||
|
echo "✅ OK"
|
||||||
|
else
|
||||||
|
echo "❌ Falló"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "📝 Logs recientes del backend:"
|
||||||
|
docker-compose logs backend --tail=5
|
||||||
5
clean.sh
Executable file
5
clean.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "🧹 Limpiando todo..."
|
||||||
|
docker-compose down -v
|
||||||
|
docker system prune -f
|
||||||
|
echo "✅ Limpieza completada"
|
||||||
12
docker-compose.override.yml
Normal file
12
docker-compose.override.yml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
backend:
|
||||||
|
command: >
|
||||||
|
sh -c "until pg_isready -h db -p 5432; do
|
||||||
|
echo 'Esperando a la base de datos...';
|
||||||
|
sleep 2;
|
||||||
|
done;
|
||||||
|
echo 'BD lista!';
|
||||||
|
python manage.py migrate;
|
||||||
|
python manage.py runserver 0.0.0.0:8000"
|
||||||
83
docker-compose.yml
Normal file
83
docker-compose.yml
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Base de datos PostgreSQL
|
||||||
|
db:
|
||||||
|
image: postgres:15
|
||||||
|
container_name: pycore_db
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: pycore_db
|
||||||
|
POSTGRES_USER: Scorpion
|
||||||
|
POSTGRES_PASSWORD: CyCoT256
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
- ./postgres/init:/docker-entrypoint-initdb.d
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
networks:
|
||||||
|
- pycore_network
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U Scorpion -d pycore_db"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
# PgAdmin
|
||||||
|
pgadmin:
|
||||||
|
image: dpage/pgadmin4
|
||||||
|
container_name: pycore_pgadmin
|
||||||
|
environment:
|
||||||
|
PGADMIN_DEFAULT_EMAIL: admin@pycore.com
|
||||||
|
PGADMIN_DEFAULT_PASSWORD: CyCoT256
|
||||||
|
ports:
|
||||||
|
- "5050:80"
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
networks:
|
||||||
|
- pycore_network
|
||||||
|
|
||||||
|
# Backend Django
|
||||||
|
backend:
|
||||||
|
build: ./backend
|
||||||
|
container_name: pycore_backend
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
ports:
|
||||||
|
- "8000:8000"
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
DATABASE_URL: postgresql://Scorpion:CyCoT256@db:5432/pycore_db
|
||||||
|
DEBUG: "True"
|
||||||
|
SECRET_KEY: "clave-secreta-temporal-2024"
|
||||||
|
networks:
|
||||||
|
- pycore_network
|
||||||
|
command: >
|
||||||
|
sh -c "echo 'Esperando a que la base de datos esté lista...' &&
|
||||||
|
sleep 10 &&
|
||||||
|
python manage.py migrate &&
|
||||||
|
python manage.py runserver 0.0.0.0:8000"
|
||||||
|
|
||||||
|
# Frontend React
|
||||||
|
frontend:
|
||||||
|
build: ./frontend
|
||||||
|
container_name: pycore_frontend
|
||||||
|
volumes:
|
||||||
|
- ./frontend:/app
|
||||||
|
- /app/node_modules
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
depends_on:
|
||||||
|
- backend
|
||||||
|
environment:
|
||||||
|
VITE_API_URL: http://localhost:8000/api
|
||||||
|
networks:
|
||||||
|
- pycore_network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
pycore_network:
|
||||||
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
12
frontend/Dockerfile
Normal file
12
frontend/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
FROM node:18-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0"]
|
||||||
12
frontend/index.html
Normal file
12
frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="es">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>pycore</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
frontend/package.json
Normal file
23
frontend/package.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "pycore-frontend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "tsc && vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"react": "^18.2.0",
|
||||||
|
"react-dom": "^18.2.0",
|
||||||
|
"react-router-dom": "^6.16.0",
|
||||||
|
"axios": "^1.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/react": "^18.2.15",
|
||||||
|
"@types/react-dom": "^18.2.7",
|
||||||
|
"@vitejs/plugin-react": "^4.0.3",
|
||||||
|
"typescript": "^5.0.2",
|
||||||
|
"vite": "^4.4.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
21
frontend/src/App.tsx
Normal file
21
frontend/src/App.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const App: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}>
|
||||||
|
<h1>🚀 pycore - ERP</h1>
|
||||||
|
<p>El sistema está funcionando correctamente.</p>
|
||||||
|
<div>
|
||||||
|
<h2>Servicios disponibles:</h2>
|
||||||
|
<ul>
|
||||||
|
<li>🌐 Frontend: http://localhost:3000</li>
|
||||||
|
<li>🔧 Backend API: http://localhost:8000</li>
|
||||||
|
<li>📊 PgAdmin: http://localhost:5050</li>
|
||||||
|
<li>🗄️ PostgreSQL: localhost:5432</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
9
frontend/src/main.tsx
Normal file
9
frontend/src/main.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
import App from './App'
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>,
|
||||||
|
)
|
||||||
10
frontend/vite.config.ts
Normal file
10
frontend/vite.config.ts
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import react from '@vitejs/plugin-react'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [react()],
|
||||||
|
server: {
|
||||||
|
host: '0.0.0.0',
|
||||||
|
port: 3000
|
||||||
|
}
|
||||||
|
})
|
||||||
174
postgres/init/01-init.sql
Normal file
174
postgres/init/01-init.sql
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
-- Script de inicialización para pycore
|
||||||
|
-- Verificar si la base de datos ya existe y solo crear tablas si no existen
|
||||||
|
|
||||||
|
-- Crear tipos ENUM personalizados si no existen
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE TYPE tipo_producto_enum AS ENUM ('insumo', 'terminado');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_object THEN null;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- 1️⃣ Sucursales
|
||||||
|
CREATE TABLE IF NOT EXISTS Sucursales (
|
||||||
|
id_sucursal SERIAL PRIMARY KEY,
|
||||||
|
nombre VARCHAR(100) NOT NULL,
|
||||||
|
direccion VARCHAR(255),
|
||||||
|
telefono VARCHAR(20),
|
||||||
|
fecha_creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 2️⃣ Inventario
|
||||||
|
CREATE TABLE IF NOT EXISTS Inventario (
|
||||||
|
id_producto SERIAL PRIMARY KEY,
|
||||||
|
nombre_producto VARCHAR(100) NOT NULL,
|
||||||
|
tipo_producto tipo_producto_enum NOT NULL,
|
||||||
|
precio_unitario DECIMAL(10,2) NOT NULL,
|
||||||
|
stock INT DEFAULT 0,
|
||||||
|
id_sucursal INT,
|
||||||
|
fecha_creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (id_sucursal) REFERENCES Sucursales(id_sucursal)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 3️⃣ Compras
|
||||||
|
CREATE TABLE IF NOT EXISTS Compras (
|
||||||
|
id_compra SERIAL PRIMARY KEY,
|
||||||
|
id_sucursal INT NOT NULL,
|
||||||
|
fecha_compra DATE NOT NULL,
|
||||||
|
total DECIMAL(10,2) NOT NULL,
|
||||||
|
FOREIGN KEY (id_sucursal) REFERENCES Sucursales(id_sucursal)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 4️⃣ Detalle_compras
|
||||||
|
CREATE TABLE IF NOT EXISTS Detalle_compras (
|
||||||
|
id_detalle SERIAL PRIMARY KEY,
|
||||||
|
id_compra INT NOT NULL,
|
||||||
|
id_producto INT NOT NULL,
|
||||||
|
cantidad INT NOT NULL,
|
||||||
|
precio_unitario DECIMAL(10,2) NOT NULL,
|
||||||
|
FOREIGN KEY (id_compra) REFERENCES Compras(id_compra),
|
||||||
|
FOREIGN KEY (id_producto) REFERENCES Inventario(id_producto)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 5️⃣ Promociones
|
||||||
|
CREATE TABLE IF NOT EXISTS Promociones (
|
||||||
|
id_promocion SERIAL PRIMARY KEY,
|
||||||
|
nombre_promocion VARCHAR(100) NOT NULL,
|
||||||
|
descripcion TEXT,
|
||||||
|
descuento DECIMAL(5,2), -- Porcentaje
|
||||||
|
fecha_inicio DATE,
|
||||||
|
fecha_fin DATE
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 6️⃣ Colaboradores
|
||||||
|
CREATE TABLE IF NOT EXISTS Colaboradores (
|
||||||
|
id_colaborador SERIAL PRIMARY KEY,
|
||||||
|
id_sucursal INT NOT NULL,
|
||||||
|
nombre VARCHAR(100) NOT NULL,
|
||||||
|
puesto VARCHAR(50),
|
||||||
|
salario DECIMAL(10,2),
|
||||||
|
fecha_ingreso DATE,
|
||||||
|
FOREIGN KEY (id_sucursal) REFERENCES Sucursales(id_sucursal)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 7️⃣ Gastos_sucursal
|
||||||
|
CREATE TABLE IF NOT EXISTS Gastos_sucursal (
|
||||||
|
id_gasto SERIAL PRIMARY KEY,
|
||||||
|
id_sucursal INT NOT NULL,
|
||||||
|
concepto VARCHAR(255) NOT NULL,
|
||||||
|
monto DECIMAL(10,2) NOT NULL,
|
||||||
|
fecha_gasto DATE NOT NULL,
|
||||||
|
FOREIGN KEY (id_sucursal) REFERENCES Sucursales(id_sucursal)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 8️⃣ Ventas
|
||||||
|
CREATE TABLE IF NOT EXISTS Ventas (
|
||||||
|
id_venta SERIAL PRIMARY KEY,
|
||||||
|
id_sucursal INT NOT NULL,
|
||||||
|
fecha_venta TIMESTAMP NOT NULL,
|
||||||
|
total DECIMAL(10,2) NOT NULL,
|
||||||
|
id_promocion INT,
|
||||||
|
FOREIGN KEY (id_sucursal) REFERENCES Sucursales(id_sucursal),
|
||||||
|
FOREIGN KEY (id_promocion) REFERENCES Promociones(id_promocion)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 9️⃣ Detalle_ventas
|
||||||
|
CREATE TABLE IF NOT EXISTS Detalle_ventas (
|
||||||
|
id_detalle SERIAL PRIMARY KEY,
|
||||||
|
id_venta INT NOT NULL,
|
||||||
|
id_producto INT NOT NULL,
|
||||||
|
cantidad INT NOT NULL,
|
||||||
|
precio_unitario DECIMAL(10,2) NOT NULL,
|
||||||
|
FOREIGN KEY (id_venta) REFERENCES Ventas(id_venta),
|
||||||
|
FOREIGN KEY (id_producto) REFERENCES Inventario(id_producto)
|
||||||
|
);
|
||||||
|
|
||||||
|
-- ==========================
|
||||||
|
-- ÍNDICES PARA MEJOR PERFORMANCE
|
||||||
|
-- ==========================
|
||||||
|
|
||||||
|
DO $$ BEGIN
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_inventario_sucursal ON Inventario(id_sucursal);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ventas_fecha ON Ventas(fecha_venta);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_ventas_sucursal ON Ventas(id_sucursal);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_compras_fecha ON Compras(fecha_compra);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_detalle_ventas_producto ON Detalle_ventas(id_producto);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_detalle_compras_producto ON Detalle_compras(id_producto);
|
||||||
|
CREATE INDEX IF NOT EXISTS idx_colaboradores_sucursal ON Colaboradores(id_sucursal);
|
||||||
|
EXCEPTION
|
||||||
|
WHEN duplicate_table THEN null;
|
||||||
|
END $$;
|
||||||
|
|
||||||
|
-- ==========================
|
||||||
|
-- DATOS DE EJEMPLO
|
||||||
|
-- ==========================
|
||||||
|
|
||||||
|
-- Insertar sucursal principal si no existen
|
||||||
|
INSERT INTO Sucursales (id_sucursal, nombre, direccion, telefono) VALUES
|
||||||
|
(1, 'Alitas Downtown', 'Av. Principal 123, Ciudad', '+52-55-1234-5678'),
|
||||||
|
(2, 'Alitas Norte', 'Plaza Norte 456, Zona Norte', '+52-55-8765-4321')
|
||||||
|
ON CONFLICT (id_sucursal) DO UPDATE SET
|
||||||
|
nombre = EXCLUDED.nombre,
|
||||||
|
direccion = EXCLUDED.direccion,
|
||||||
|
telefono = EXCLUDED.telefono;
|
||||||
|
|
||||||
|
-- Insertar productos típicos de alitas
|
||||||
|
INSERT INTO Inventario (id_producto, nombre_producto, tipo_producto, precio_unitario, stock, id_sucursal) VALUES
|
||||||
|
(1, 'Alitas de pollo', 'insumo', 45.50, 200, 1),
|
||||||
|
(2, 'Salsa BBQ', 'insumo', 25.00, 50, 1),
|
||||||
|
(3, 'Salsa Buffalo', 'insumo', 28.00, 40, 1),
|
||||||
|
(4, 'Papas para freír', 'insumo', 18.00, 100, 1),
|
||||||
|
(5, 'Harina para empanizar', 'insumo', 12.50, 30, 1),
|
||||||
|
(6, 'Orden de alitas (6 pzas)', 'terminado', 120.00, 0, 1),
|
||||||
|
(7, 'Orden de alitas (12 pzas)', 'terminado', 220.00, 0, 1),
|
||||||
|
(8, 'Papas a la francesa', 'terminado', 45.00, 0, 1),
|
||||||
|
(9, 'Aros de cebolla', 'terminado', 55.00, 0, 1)
|
||||||
|
ON CONFLICT (id_producto) DO UPDATE SET
|
||||||
|
nombre_producto = EXCLUDED.nombre_producto,
|
||||||
|
tipo_producto = EXCLUDED.tipo_producto,
|
||||||
|
precio_unitario = EXCLUDED.precio_unitario,
|
||||||
|
stock = EXCLUDED.stock,
|
||||||
|
id_sucursal = EXCLUDED.id_sucursal;
|
||||||
|
|
||||||
|
-- Insertar promociones
|
||||||
|
INSERT INTO Promociones (id_promocion, nombre_promocion, descripcion, descuento, fecha_inicio, fecha_fin) VALUES
|
||||||
|
(1, 'Martes de Alitas', '2x1 en órdenes de alitas todos los martes', 50.00, '2024-01-01', '2024-12-31'),
|
||||||
|
(2, 'Happy Hour', '20% de descuento en bebidas de 4pm a 7pm', 20.00, '2024-01-01', '2024-12-31'),
|
||||||
|
(3, 'Combo Familiar', 'Descuento especial en combos familiares', 15.00, '2024-03-01', '2024-03-31')
|
||||||
|
ON CONFLICT (id_promocion) DO UPDATE SET
|
||||||
|
nombre_promocion = EXCLUDED.nombre_promocion,
|
||||||
|
descripcion = EXCLUDED.descripcion,
|
||||||
|
descuento = EXCLUDED.descuento,
|
||||||
|
fecha_inicio = EXCLUDED.fecha_inicio,
|
||||||
|
fecha_fin = EXCLUDED.fecha_fin;
|
||||||
|
|
||||||
|
-- Insertar colaboradores
|
||||||
|
INSERT INTO Colaboradores (id_colaborador, id_sucursal, nombre, puesto, salario, fecha_ingreso) VALUES
|
||||||
|
(1, 1, 'Juan Pérez García', 'Gerente', 15000.00, '2023-01-15'),
|
||||||
|
(2, 1, 'María Hernández López', 'Cocinero', 8000.00, '2023-03-20'),
|
||||||
|
(3, 1, 'Carlos Rodríguez Silva', 'Mesero', 6000.00, '2023-05-10')
|
||||||
|
ON CONFLICT (id_colaborador) DO UPDATE SET
|
||||||
|
id_sucursal = EXCLUDED.id_sucursal,
|
||||||
|
nombre = EXCLUDED.nombre,
|
||||||
|
puesto = EXCLUDED.puesto,
|
||||||
|
salario = EXCLUDED.salario,
|
||||||
|
fecha_ingreso = EXCLUDED.fecha_ingreso;
|
||||||
24
start.sh
Executable file
24
start.sh
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "🚀 Iniciando pycore ..."
|
||||||
|
|
||||||
|
# Verificar Docker
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo "❌ Docker no está instalado"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Construir y levantar
|
||||||
|
echo "📦 Construyendo contenedores..."
|
||||||
|
docker-compose up --build -d
|
||||||
|
|
||||||
|
echo "⏳ Esperando inicialización..."
|
||||||
|
sleep 15
|
||||||
|
|
||||||
|
echo "✅ Servicios iniciados:"
|
||||||
|
echo " 🌐 Frontend: http://localhost:3000"
|
||||||
|
echo " 🔧 Backend: http://localhost:8000"
|
||||||
|
echo " 📊 PgAdmin: http://localhost:5050"
|
||||||
|
echo " 🗄️ PostgreSQL: localhost:5432"
|
||||||
|
echo ""
|
||||||
|
echo "🔑 PgAdmin: admin@pycore.com / CyCoT256"
|
||||||
Reference in New Issue
Block a user