diff --git a/README.md b/README.md index 52d59f0..95f656e 100644 --- a/README.md +++ b/README.md @@ -1 +1,62 @@ -# PGPI-G1.11 \ No newline at end of file +# ESSENZA + +Plataforma de comercio electrónico para la gestión y venta de productos y servicios cosméticos. + +## ⚡ Inicio Rápido + +Acceso a la aplicación desplegada: +**[🌐 https://pgpi-g1-11.onrender.com/](https://pgpi-g1-11.onrender.com/)** + +## 📚 Documentación + +Para aprender a utilizar la plataforma, consulta nuestra guía: + +> **[👤 Manual de Usuario](./essenza/manual_usuario.md)** +> +> *Incluye instrucciones paso a paso para el registro, proceso de compra, seguimiento de pedidos y gestión del panel de administración.* + +## 📂 Estructura del Proyecto + +~~~text +PGPI-G1.11/ +├── docs/ # Documentación completa de planificación y desarrollo +├── essenza/ # Código fuente del backend (Raíz del proyecto) +│ ├── _sample_assets/ # Imágenes de sampleo +│ ├── cart/ # App de gestión del carrito de compra +│ ├── essenza/ # Configuración principal del proyecto Django +│ ├── info/ # App de información general +│ ├── order/ # App de gestión de pedidos y pagos +│ │ └── samples/ # JSON con pedidos de sampleo +│ ├── product/ # App de catálogo y gestión de productos +│ │ └── samples/ # JSON con productos de sampleo +│ ├── static/ # Recursos estáticos +│ │ └── images/ +│ ├── templates/ # Plantillas HTML +│ ├── user/ # App de autenticación y gestión de usuarios +│ │ └── samples/ # JSON con usuarios de sampleo +│ ├── deploy.sh # Script de construcción para Render (Linux) +│ ├── Dockerfile # Definición de imagen para contenedor Docker +│ ├── entrypoint.sh # Script de arranque del contenedor +│ ├── install.bat # Script de instalación de entorno local (Windows) +│ ├── manage.py # Gestor de línea de comandos Django +│ ├── manual_usuario.md # Guía funcional para el usuario final +│ ├── Procfile # Comando de inicio para Render +│ ├── requirements.txt # Lista de dependencias del proyecto +│ └── reset_db.bat # Script de reinicio y poblado de BBDD +├── .gitignore # Archivos excluidos del control de versiones +└── README.md +~~~ + +--- + +
+

PGPI - Grupo 1.11

+

+ Francisco de Castro • + Celia Suárez • + Carolina Murillo • + Javier Gea • + Alejandro Mantecón +

+

Curso 2025/2026

+
\ No newline at end of file diff --git a/essenza/Dockerfile b/essenza/Dockerfile new file mode 100644 index 0000000..7dffc4f --- /dev/null +++ b/essenza/Dockerfile @@ -0,0 +1,32 @@ +# Usamos Python 3.10 (ajustado para compatibilidad) +FROM python:3.10-slim + +# Evita que Python genere archivos .pyc y buffer de salida +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# Directorio de trabajo dentro del contenedor +WORKDIR /app + +# Instalamos dependencias del sistema necesarias para compilar algunas librerías +RUN apt-get update && apt-get install -y --no-install-recommends \ + gcc \ + libpq-dev \ + && rm -rf /var/lib/apt/lists/* + +# Instalamos dependencias de Python +COPY requirements.txt /app/ +RUN pip install --upgrade pip && pip install -r requirements.txt + +# Copiamos todo el código +COPY . /app/ + +# Copiamos y damos permisos al script de entrada +COPY entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +# Exponemos el puerto 8000 +EXPOSE 8000 + +# Ejecutamos el script al iniciar +ENTRYPOINT ["/app/entrypoint.sh"] \ No newline at end of file diff --git a/essenza/entrypoint.sh b/essenza/entrypoint.sh new file mode 100644 index 0000000..95b1488 --- /dev/null +++ b/essenza/entrypoint.sh @@ -0,0 +1,32 @@ +#!/bin/sh +set -e + +echo "--- 1. Instalando dependencias (pip) ---" +pip install -r requirements.txt + +echo "--- 2. Generando migraciones ---" +python manage.py makemigrations + +echo "--- 3. Recolectando estáticos ---" +python manage.py collectstatic --no-input + +echo "--- 4. Vaciando DB (Flush) ---" +python manage.py flush --no-input + +echo "--- 5. Aplicando Migraciones (Migrate) ---" +python manage.py migrate --no-input + +echo "--- 6. Copiando imagenes de sampleo ---" +mkdir -p media +cp -r _sample_assets/* media/ 2>/dev/null || true + +echo "--- 7. Cargando datos de USER, PRODUCT, ORDER ---" +python manage.py loaddata user/sample/sample.json +python manage.py loaddata product/sample/sample.json +python manage.py loaddata order/sample/sample.json + +echo "======================================================" +echo "!PROCESO COMPLETADO! INICIANDO SERVIDOR EN PUERTO 8000" +echo "======================================================" + +exec python manage.py runserver 0.0.0.0:8000 \ No newline at end of file diff --git a/essenza/install.bat b/essenza/install.bat new file mode 100644 index 0000000..48e1d39 --- /dev/null +++ b/essenza/install.bat @@ -0,0 +1,61 @@ +@echo off +REM --------------------------------------------------------- +REM NOMBRE: install.bat +REM FUNCION: Prepara el entorno tecnico desde cero. +REM 1. Verifica entorno virtual. +REM 2. Instala dependencias. +REM 3. Crea archivos de migracion (Detecta modelos). +REM 4. Aplica migraciones (Crea tablas vacias). +REM 5. Recolecta staticfiles. +REM --------------------------------------------------------- + +IF "%VIRTUAL_ENV%"=="" ( + echo. + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + echo ERROR: No se detecta un entorno virtual activo. + echo Por favor, activa tu '.venv' antes de ejecutar este script. + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + pause + exit /b 1 +) + +echo. +echo --- 1. Instalando dependencias del sistema... +pip install -r requirements.txt +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo --- 2. Generando archivos de migracion modularmente... +python manage.py makemigrations cart +python manage.py makemigrations order +python manage.py makemigrations product +python manage.py makemigrations user +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo --- 3. Construyendo la Base de Datos... +python manage.py migrate --noinput +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo --- 4. Recolectando staticfiles... +python manage.py collectstatic --noinput +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo ======================================================= +echo !INSTALACION COMPLETADA! +echo Estructura de BD creada exitosamente. +echo Para poblar con datos de ejemplo, ejecuta: reset_db.bat +echo ======================================================= +GOTO :END + +:ERROR +echo. +echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +echo ERROR CRITICO -> La instalacion ha fallado. +echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +pause +exit /b 1 + +:END \ No newline at end of file diff --git a/essenza/load_samples.bat b/essenza/load_samples.bat deleted file mode 100644 index be0c428..0000000 --- a/essenza/load_samples.bat +++ /dev/null @@ -1,76 +0,0 @@ -@echo off -REM --------------------------------------------------------- -REM IMPORTANTE: Este archivo RESTAURA TOTALMENTE la BD del proyecto. -REM 1. Verifica entorno virtual. -REM 2. Instala dependencias. -REM 3. Borra BD y Media. -REM 4. Recrea BD y copia assets de sampleo. -REM --------------------------------------------------------- - -IF "%VIRTUAL_ENV%"=="" ( - echo. - echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - echo ERROR: No se detecta un entorno virtual activo. - echo Por favor, activa tu '.venv' antes de ejecutar este script. - echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - pause - exit /b 1 -) - -echo. -echo --- Instalando dependencias (pip)... -pip install -r requirements.txt -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Borrando TODOS los datos de la BD... -python manage.py flush --noinput -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Aplicando migraciones... -python manage.py migrate --noinput -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Copiando imagenes de sampleo a 'media/'... -REM XCOPY [origen] [destino] /E /I /Y -REM /E = Copia subdirectorios (incluso vacíos) -REM /I = Si el destino no existe, asume que es un directorio -REM /Y = Suprime la pregunta de "sobreescribir archivo" -XCOPY _sample_assets media /E /I /Y -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Cargando datos de USER... -python manage.py loaddata user/sample/sample.json -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Cargando datos de PRODUCT... -python manage.py loaddata product/sample/sample.json -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo --- Cargando datos de ORDER... -python manage.py loaddata order/sample/sample.json -IF %ERRORLEVEL% NEQ 0 GOTO :ERROR - -echo. -echo ======================================================== -echo !PROCESO COMPLETADO CON EXITO! -echo Los datos de sampleo se han cargado en la base de datos. -echo ======================================================== -GOTO :END - -:ERROR -echo. -echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -echo ERROR -> El script se detuvo porque un comando ha fallado. -echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -pause -exit /b 1 - -:END - -@echo on \ No newline at end of file diff --git a/essenza/manual_usuario.md b/essenza/manual_usuario.md new file mode 100644 index 0000000..c522d9e --- /dev/null +++ b/essenza/manual_usuario.md @@ -0,0 +1,186 @@ +# MANUAL DE USUARIO · ESSENZA + +## 0. Índice + +1. [Introducción](#1-introducción) +2. [Registro e Inicio de Sesión](#2-registro-e-inicio-de-sesión) + * [2.1. Registro de usuario](#21-registro-de-usuario) + * [2.2. Inicio de sesión](#22-inicio-de-sesión) +3. [Usuario NO registrado (Invitado)](#3-usuario-no-registrado-invitado) + * [3.1. Acciones permitidas](#31-acciones-permitidas) + * [3.2. Carrito de Compra](#32-carrito-de-compra) +4. [Usuario Registrado (Cliente)](#4-usuario-registrado-cliente) + * [4.1. Perfil del Usuario](#41-perfil-del-usuario) + * [4.2. Mis Pedidos](#42-mis-pedidos) +5. [Administrador](#5-administrador) + * [5.1. Gestión de Stock](#51-gestión-de-stock) + * [5.2. Gestión de Productos](#52-gestión-de-productos) + * [5.3. Creación de Productos](#53-creación-de-productos) + * [5.4. Gestión de Pedidos](#54-gestión-de-pedidos) + * [5.5. Gestión de Usuarios](#55-gestión-de-usuarios) + * [5.6. Reportes Administrativos](#56-reportes-administrativos) +6. [Resumen de acciones por rol](#6-resumen-de-acciones-por-rol) + +--- + +## 1. Introducción + +**Essenza** es una aplicación web dedicada a la venta de productos y servicios de cosmética. + +**Los usuarios pueden:** +* Navegar por el escaparate y el catálogo completo. +* Añadir productos al carrito de compra. +* Realizar compras mediante **Tarjeta** o **Contrarreembolso**. +* Localizar pedidos específicos mediante identificador de seguimiento. +* Consultar el historial y estado de sus pedidos (solo usuarios registrados). + +**El personal de administración dispone de un panel especializado para:** +* Administrar el stock e inventario. +* Crear, editar y eliminar productos. +* Gestionar el estado de los pedidos. +* Administrar cuentas de usuarios. +* Analizar el rendimiento de la tienda mediante reportes. + +Este manual detalla el uso de la plataforma según los tres roles disponibles: **Invitado**, **Cliente** y **Administrador**. + +--- + +## 2. Registro e Inicio de Sesión + +### 2.1. Registro de usuario + +Para crear una cuenta nueva y acceder a las funciones de fidelización: + +1. Pulse el **icono de usuario** situado en la esquina superior derecha de la barra de navegación. +2. Seleccione la opción **Registrarse**. +3. Complete el formulario con sus datos personales (Nombre, Email, Contraseña). +4. Confirme el registro. + +### 2.2. Inicio de sesión + +Si ya dispone de cuenta: + +1. Pulse el **icono de usuario**. +2. Seleccione **Iniciar sesión**. +3. Introduzca sus credenciales: + * **Correo electrónico**. + * **Contraseña**. +4. Pulse el botón de entrar. + +--- + +## 3. Usuario NO registrado (Invitado) + +Un usuario invitado puede navegar libremente por la tienda, pero tiene acceso limitado a la gestión de datos. + +### 3.1. Acciones permitidas + +* **Información Legal:** Puede consultar los términos y condiciones pulsando el icono informativo situado en la barra de navegación (esquina superior izquierda). +* **Catálogo:** Acceso completo al escaparate, uso de filtros por categoría y barra de búsqueda. +* **Compra:** Posibilidad de añadir items al carrito y finalizar la compra sin registrarse. +* **Localiza tu envío:** Herramienta para consultar el estado de un pedido puntual. + 1. Acceda a la sección "Localiza tu envío". + 2. Introduzca el **ID de seguimiento** (recibido por email). + 3. Introduzca el **email** utilizado en la compra. + 4. El sistema mostrará el estado actual del pedido. + +### 3.2. Carrito de Compra + +El carrito permite gestionar la compra antes del pago: +* **Gestión:** Modificar cantidades (+) (-) o eliminar productos (papelera). +* **Resumen:** Visualización clara del subtotal y costes de envío. +* **Pago:** Selección del método de pago. + +#### 3.2.1. Pago a contrarreembolso +Al seleccionar la opción **Efectivo**: +1. Se solicitará un formulario con los datos de envío (Dirección, Ciudad, CP). +2. Al pulsar **Finalizar compra**, el pedido se guarda con estado "Pendiente" y se paga al recibirlo. + +#### 3.2.2. Pago con tarjeta (Stripe) +Al seleccionar **Tarjeta**: +1. El usuario es redirigido a la pasarela de pago segura de Stripe. +2. Se introducen los datos bancarios (Número de tarjeta, Fecha, CVC). +3. Tras la validación, el usuario regresa automáticamente a Essenza con la confirmación del pedido. + +--- + +## 4. Usuario Registrado (Cliente) + +Tras iniciar sesión, el cliente obtiene persistencia de datos y acceso al área personal. + +### 4.1. Perfil del Usuario +Desde el panel de perfil, accesible desde el menú de usuario, es posible: +* Visualizar foto, nombre, apellidos y correo asociado. +* **Editar datos:** Modificar información personal o actualizar la foto de perfil. +* **Eliminar cuenta:** Opción para borrar permanentemente los datos del usuario (requiere doble confirmación por seguridad). + +### 4.2. Mis Pedidos +Sección exclusiva para clientes que muestra el historial completo de compras. +* **Vista General:** Lista de todos los pedidos realizados, mostrando fecha, total y estado actual. +* **Vista Detallada:** Haciendo clic en cualquier pedido, se despliega el desglose de productos comprados, dirección de envío utilizada y desglose de cargos. + +--- + +## 5. Administrador + +El rol Administrador tiene acceso al Panel de Gestión Interno para controlar la operativa del negocio. + +### 5.1. Gestión de Stock +Permite visualizar el inventario en tiempo real. +* El administrador puede localizar cualquier producto y **modificar la cifra de stock** directamente. +* Los cambios se reflejan inmediatamente en la web (si el stock llega a 0, el producto aparecerá como "Agotado"). + +### 5.2. Gestión de Productos +Listado maestro de todos los artículos de la tienda. +* Permite buscar productos por nombre, así como filtrarlos. +* Permite **Editar** productos existentes (cambiar precios, descripciones o fotos). +* Permite **Eliminar** productos del catálogo. + +### 5.3. Creación de Productos +Formulario para dar de alta nuevas referencias en la tienda. Campos requeridos: +* **Nombre y Descripción:** Información visible para el cliente. +* **Categoría y Marca:** Para los filtros de búsqueda. +* **Precio:** Valor unitario. +* **Foto (opcional):** Archivo `.jpg` o `.png` representativo. +* **Producto activo:** Disponibilidad para la venta. + +### 5.4. Gestión de Pedidos +Bandeja de entrada de todas las compras realizadas por los usuarios. +* Permite filtrar pedidos por estado (En preparación, Enviados, Entregados). +* Permite ver los detalles de cada pedido. + +#### 5.4.1. Cambio de estado de pedido +Funcionalidad crítica para el flujo de trabajo: +1. El administrador entra en el detalle de un pedido. +2. Selecciona el nuevo estado en la barra del mismo (ej. cambiar de *Pendiente* a *Enviado* cuando sale del almacén). +3. Al guardar, el usuario verá el nuevo estado en su sección "Mis Pedidos" o en el localizador de envíos. + +### 5.5. Gestión de Usuarios +Panel para administrar la base de datos de clientes. +* Permite ver la lista de usuarios registrados. +* Permite ver detalles de contacto. +* Permite desactivar o bloquear usuarios en caso de actividad sospechosa. + +### 5.6. Reportes Administrativos +Cuadro de mandos visual para la toma de decisiones. Muestra gráficas generadas automáticamente sobre: +* **Historial de Ventas:** Listado de todas las ventas realizadas en la web. +* **Productos Top:** Artículos más vendidos. +* **Usuarios Top:** Usuarios con mayor número de gastos realizados. + +--- + +## 6. Resumen de acciones por rol + +| Acción | Invitado | Registrado | Administrador | +| :--- | :---: | :---: | :---: | +| **Ver productos** | ✔ | ✔ | ✔ | +| **Buscar / Filtros** | ✔ | ✔ | ✔ | +| **Añadir al carrito** | ✔ | ✔ | ❌ | +| **Finalizar compra** | ✔ | ✔ | ❌ | +| **Listar TODOS mis pedidos** | ❌ | ✔ | ❌ | +| **Seguimiento de pedido** | ✔ | ✔ | ❌ | +| **Ver TODOS los pedidos (Global)** | ❌ | ❌ | ✔ | +| **Crear / Editar productos** | ❌ | ❌ | ✔ | +| **Actualizar stock** | ❌ | ❌ | ✔ | +| **Gestionar usuarios** | ❌ | ❌ | ✔ | +| **Ver ventas** | ❌ | ❌ | ✔ | \ No newline at end of file diff --git a/essenza/order/tests.py b/essenza/order/tests.py index f9f930f..f98eea3 100644 --- a/essenza/order/tests.py +++ b/essenza/order/tests.py @@ -55,7 +55,7 @@ def _create_cart_for_user(self, quantity=1): return cart # ========================================== - # BLOQUE 1: CONTRARREMBOLSO (COD) + # BLOQUE 1: CONTRARREEMBOLSO (COD) # ========================================== def test_cod_checkout_success(self): """ @@ -231,7 +231,7 @@ def test_guest_checkout_cod(self): } session.save() - # 2. Pagar Contrarrembolso + # 2. Pagar Contrarreembolso data = { "payment_method": "cod", "shipping_name": "Invitado", diff --git a/essenza/order/views.py b/essenza/order/views.py index f85b2cd..60aca21 100644 --- a/essenza/order/views.py +++ b/essenza/order/views.py @@ -298,7 +298,7 @@ def create_checkout(request): payment_method = request.POST.get("payment_method") # 'stripe' o 'cod' - # --- OPCIÓN A: CONTRARREMBOLSO (COD) --- + # --- OPCIÓN A: CONTRARREEMBOLSO (COD) --- if payment_method == "cod": # 1. Capturamos los datos DEL FORMULARIO HTML name = request.POST.get("shipping_name") diff --git a/essenza/reset_db.bat b/essenza/reset_db.bat new file mode 100644 index 0000000..4fae7b8 --- /dev/null +++ b/essenza/reset_db.bat @@ -0,0 +1,83 @@ +@echo off +REM --------------------------------------------------------- +REM NOMBRE: reset_db.bat +REM FUNCION: restaura los datos de sampleo de la base de datos. +REM 1. Borra la base de datos. +REM 2. Verifica estado y estructura de tablas. +REM 3. Copia assets multimedia. +REM 4. Carga fixtures. +REM --------------------------------------------------------- + +IF "%VIRTUAL_ENV%"=="" ( + echo. + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + echo ERROR: No se detecta un entorno virtual activo. + echo Por favor, activa tu '.venv' antes de ejecutar este script. + echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + pause + exit /b 1 +) + +echo. +echo !ADVERTENCIA!: Se borraran todos los datos actuales de la BD. + +echo. +echo --- 1. Eliminando Base de Datos antigua (si la hay)... +IF EXIST db.sqlite3 ( + REM DEL /F /Q [archivo] + REM /F = Fuerza la eliminacion (borra archivos de "Solo lectura") + REM /Q = Modo silencioso (Suprime la confirmacion S/N) + DEL /F /Q db.sqlite3 + echo Archivo db.sqlite3 eliminado. +) ELSE ( + echo No se encontro db.sqlite3, se creara una nueva. +) + +echo. +echo --- 2. Verificando estado y estructura de tablas... +python manage.py makemigrations cart +python manage.py makemigrations order +python manage.py makemigrations product +python manage.py makemigrations user +python manage.py migrate --noinput +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo --- 3. Restaurando imagenes de sampleo en 'media/'... +REM XCOPY [origen] [destino] /E /I /Y +REM /E = Copia subdirectorios (incluso vacíos) +REM /I = Si el destino no existe, asume que es un directorio +REM /Y = Suprime la pregunta de "sobreescribir archivo" +XCOPY _sample_assets media /E /I /Y +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo --- 4. Cargando datos de prueba... +echo Cargando Usuarios... +python manage.py loaddata user/sample/sample.json +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo Cargando Productos... +python manage.py loaddata product/sample/sample.json +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo Cargando Pedidos... +python manage.py loaddata order/sample/sample.json +IF %ERRORLEVEL% NEQ 0 GOTO :ERROR + +echo. +echo ====================================================== +echo !RESETEO COMPLETADO! +echo La aplicacion ha vuelto al estado de fabrica (Sample). +echo ====================================================== +GOTO :END + +:ERROR +echo. +echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +echo ERROR -> Fallo al cargar los datos. Revisa los logs. +echo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +pause +exit /b 1 + +:END \ No newline at end of file diff --git a/essenza/templates/cart/cart_detail.html b/essenza/templates/cart/cart_detail.html index 51e0834..c9dd650 100644 --- a/essenza/templates/cart/cart_detail.html +++ b/essenza/templates/cart/cart_detail.html @@ -409,7 +409,7 @@

Efectivo

-

Datos de Envío para Contrarrembolso

+

Datos de Envío para Contrarreembolso