| Sistema / Proyecto: | MercariX POS & Control de Inventario |
| Versión del Sistema: | 1.0.0 Pro (Enterprise Edition) |
| Fecha de Emisión: | Agosto 2026 |
| Entorno Recomendado: | WampServer / XAMPP (Apache, PHP 8.x, MySQL 5.7/8.0) |
| Estado del Sistema: | Producción / Desplegado en Localhost (Puerto 80 y 3000) |
El sistema MercariX POS es una solución integral de punto de venta desarrollada bajo una arquitectura desacoplada de alto rendimiento. Combina un potente backend ligero en PHP Orientado a Objetos con PDO y una interfaz reactiva SPA (Single Page Application) construida en React 18.
El sistema implementa el patrón de arquitectura desacoplada REST. La capa de almacenamiento y procesamiento reside en la carpeta /backend, mientras que el cliente de usuario se procesa en /frontend o mediante el punto de entrada directo en index.php.
c:\wamp64\www\fotoislena\
├── backend/
│ ├── config/
│ │ └── database.php # Conexión PDO, UTF-8 y Headers CORS
│ ├── api/
│ │ ├── auth.php # Autenticación y JWT/Tokens
│ │ ├── users.php # CRUD de usuarios (Admin y Auxiliares)
│ │ ├── categories.php # Gestión de categorías de productos
│ │ ├── products.php # Inventario y generador EAN/Code128
│ │ ├── customers.php # Directorio de clientes y cupos
│ │ ├── sales.php # Checkout POS (Efectivo, Nequi, Crédito)
│ │ ├── credit.php # Registro de abonos y comprobación "Al día"
│ │ ├── cash_session.php # Apertura, cierre y auditoría de caja
│ │ ├── whatsapp.php # Generador de enlaces y Cron Día 30
│ │ └── dashboard.php # Métricas de ganancias y ventas
│ ├── database.sql # Esquema DDL de creación de tablas
│ └── install.php # Auto-instalador y migrador de esquema
├── frontend/
│ ├── src/
│ │ ├── api/index.js # Cliente HTTP API global (Fetch wrapper)
│ │ ├── context/AuthContext.jsx # Proveedor global de sesión de usuario
│ │ ├── components/
│ │ │ ├── Navbar.jsx # Estado visual de caja y perfil
│ │ │ ├── Sidebar.jsx # Navegación del sistema
│ │ │ ├── Modal.jsx # Componente contenedor modal accesible
│ │ │ ├── CashSessionModal.jsx # Apertura y cierre de caja
│ │ │ ├── ReceiptModal.jsx # Comprobante impreso POS
│ │ │ ├── UpToDateAlert.jsx # Modal modal "¡El usuario está al día!"
│ │ │ └── BarcodeVisualizer.jsx # Renderizador de etiquetas Barcode
│ │ └── pages/
│ │ ├── Dashboard.jsx # Estadísticas y métricas
│ │ ├── PosTerminal.jsx # Caja registradora e íconos de cobro
│ │ ├── Inventory.jsx # Gestión de catálogo y stock
│ │ ├── CreditManager.jsx # Fiados, cobro y WhatsApp Día 30
│ │ ├── Customers.jsx # Directorio de clientes
│ │ └── UsersManager.jsx # Control de usuarios y roles
│ ├── index.html # Plantilla base Vite
│ └── vite.config.js # Configuración de compilación Vite
├── index.php # SPA autocontenida ejecutable en WampServer
└── manual_programador.html # Documento manual del programador
La base de datos se denomina fotoislena_pos y utiliza el motor InnoDB con codificación utf8mb4_unicode_ci para máxima integridad referencial y soporte de caracteres.
| Tabla | Descripción | Llave Primaria | Llaves Foráneas principales |
|---|---|---|---|
users |
Almacena cuentas de acceso (Admin y Auxiliar) | id |
N/A |
categories |
Categorías del catálogo (Comestibles, Aseo, etc.) | id |
N/A |
products |
Catálogo de inventario, costo, precio y barcode | id |
category_id -> categories.id |
customers |
Clientes registrados, cupo de crédito y deuda | id |
N/A |
sales |
Encabezado de facturas de venta POS | id |
user_id -> users.id, customer_id -> customers.id |
sale_items |
Detalle de ítems y productos por factura | id |
sale_id -> sales.id, product_id -> products.id |
credit_payments |
Registro histórico de abonos a deudas fiadas | id |
customer_id -> customers.id, user_id -> users.id |
cash_sessions |
Turnos de caja (Apertura, Cierre y Arqueo) | id |
user_id -> users.id |
whatsapp_logs |
Historial de mensajes de cobro enviados | id |
customer_id -> customers.id |
CREATE TABLE `sales` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`invoice_number` VARCHAR(50) NOT NULL UNIQUE,
`user_id` INT NOT NULL,
`customer_id` INT DEFAULT NULL,
`subtotal` DECIMAL(10,2) NOT NULL,
`tax` DECIMAL(10,2) DEFAULT 0.00,
`total_amount` DECIMAL(10,2) NOT NULL,
`payment_method` ENUM('cash', 'nequi', 'credit') NOT NULL DEFAULT 'cash',
`nequi_reference` VARCHAR(50) DEFAULT NULL,
`status` ENUM('paid', 'pending_credit', 'cancelled') NOT NULL DEFAULT 'paid',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`),
FOREIGN KEY (`customer_id`) REFERENCES `customers`(`id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
| Endpoint | Método | Parámetros / Body | Descripción / Respuesta |
|---|---|---|---|
/api/auth.php?action=login |
POST | {email, password} |
Autentica al usuario y retorna datos de perfil y token. |
/api/products.php |
GET | search, category_id |
Retorna lista de productos filtrados con stock y precio. |
/api/products.php?action=generate_barcode |
GET | N/A | Genera código EAN/Code128 único de 12 dígitos (770...). |
/api/sales.php |
POST | {user_id, customer_id, payment_method, nequi_reference, items} |
Procesa la venta, descuenta stock de inventario y genera factura. |
/api/credit.php |
POST | {customer_id, user_id, amount, notes} |
Registra abono a la deuda. Si saldo=0, retorna is_up_to_date: true. |
/api/cash_session.php?action=status |
GET | user_id |
Verifica si la caja está abierta y calcula saldo esperado. |
/api/cash_session.php?action=close |
POST | {user_id, closing_amount, notes} |
Cierra caja, audita dinero contado y calcula diferencia/faltante. |
/api/whatsapp.php?action=day30_reminders |
GET | N/A | Obtiene lista de deudores y enlaces WhatsApp para el corte del día 30. |
/api/dashboard.php |
GET | N/A | Retorna totales de ventas, cartera fiada, top productos y ganancias netas. |
El cliente frontend utiliza React en arquitectura funcional pura con Hooks (useState, useEffect, useRef, useContext).
localStorage con parseo seguro blindado ante excepciones.
Permite ingresar productos escaneando con pistola lectora USB sobre el campo con autofocus o seleccionándolos del catálogo. Soporta 3 métodos de pago:
Garantiza que no se realicen ventas sin una caja abierta previamente. Al cierre, calcula:
Efectivo Esperado = Fondo Inicial Base + Ventas en Efectivo + Abonos en Efectivo
Diferencia / Descuadre = Efectivo Físico Contado - Efectivo Esperado
Permite enviar mensajes personalizados de cobro mediante enlaces directos a la API de WhatsApp con formato encoded. El sistema programa el envío masivo para todos los días 30 de cada mes.
c:\wamp64\www\fotoislena.http://localhost/fotoislena/backend/install.phpfotoislena_pos, aplicará las migraciones y poblará los usuarios demo.Para ejecutar automáticamente la revisión de deudores cada día 30 a las 9:00 AM, agregar la siguiente línea a la tabla de Cron de Apache/Linux o en Windows Task Scheduler:
0 9 30 * * curl -s http://localhost/fotoislena/backend/api/whatsapp.php?action=day30_reminders
mysqldump -u root fotoislena_pos > respaldo_fotoislena.sql
A continuación se presentan los diagramas de modelado formal de arquitectura y comportamiento del sistema MercariX POS:
Muestra las interacciones operativas agrupadas por los tres actores del sistema (Auxiliar de Caja, Administrador POS y SuperAdministrador Global).
Estructura de entidades orientada a objetos y relaciones de base de datos MySQL / PDO:
| Clase / Entidad | Atributos Principales | Métodos de Dominio | Relaciones |
|---|---|---|---|
User |
id, name, email, password, role, company_name, status | login(), changePassword(), toggleStatus() | 1 -> N Sales, 1 -> N CashSessions |
License |
id, business_name, owner_email, license_key, plan_type, max_users | generateKey(), extendLicense() | 1 -> N Users (vía max_users) |
CompanySetting |
id, company_name, nit, address, phone, logo_url, footer_text | updateSettings() | 1 -> 1 Microempresa |
Product |
id, barcode, name, category_id, cost_price, sale_price, stock | generateBarcode(), updateStock() | N -> 1 Category, 1 -> N SaleDetails |
Customer |
id, document, name, phone, credit_limit, current_debt | recordAbono(), isUpToDate() | 1 -> N Sales, 1 -> N Payments |
Sale |
id, invoice_number, user_id, customer_id, total_amount, payment_method | calculateTotal(), processCheckout() | 1 -> N SaleDetails |
CashSession |
id, user_id, opening_amount, cash_sales, closing_amount, difference | calculateExpected(), closeSession() | N -> 1 User |
1. [Cajero] ──────────> (Escanea Barcode / Agrega ítems) ─────────> [POS Terminal React]
2. [POS Terminal] ───> (Calcula Subtotal y Selecciona Método) ───> [POS Terminal React]
3. [POS Terminal] ───> POST /api/sales.php (items, payment) ──────> [Backend API Sales]
4. [Backend API] ────> START TRANSACTION ─────────────────────────> [MySQL Database]
5. [Backend API] ────> INSERT INTO sales & sale_items ────────────> [MySQL Database]
6. [Backend API] ────> UPDATE products SET stock = stock - qty ──> [MySQL Database]
7. [MySQL DB] ───────> COMMIT TRANSACTION ─────────────────────────> [Backend API Sales]
8. [Backend API] ────> HTTP 200 OK {status: success, invoice} ────> [POS Terminal React]
9. [POS Terminal] ───> Limpia Carrito & Abre ReceiptModal ───────> [Cajero (Imprime)]
1. [SuperAdmin / Admin] ──> Clic en "➕ Registrar Usuario" ──────────> [UsersManager UI]
2. [UsersManager UI] ────> POST /api/users.php (action: create) ───> [Backend API Users]
3. [Backend API Users] ──> SELECT COUNT(*) FROM users WHERE co=? ──> [MySQL Database]
4. [Backend API Users] ──> SELECT max_users FROM licenses ─────────> [MySQL Database]
5. [Backend API Users] ──> ¿total_users >= max_users? ────────────> [Evaluación Límite]
├── SI (Excedido): ──> HTTP 400 Bad Request ("Límite alcanzado") ──> [Muestra Alerta Roja]
└── NO (Permitido): ─> INSERT INTO users (hash, role, status) ───> [Crea Usuario OK]
1. [Cajero] ──────────> Clic "🔒 Cierre de Caja" ─────────────────> [CashSessionModal]
2. [CashSessionModal] > GET /api/cash_session.php?action=status ─> [Backend API]
3. [Backend API] ─────> Suma Fondo Base + Ventas Cash + Abonos ───> [MySQL Database]
4. [Backend API] ─────> Retorna Efectivo Esperado en Caja ($ COP) -> [CashSessionModal]
5. [Cajero] ──────────> Ingresa Efectivo Físico Contado ($ COP) ────> [CashSessionModal]
6. [CashSessionModal] > POST /api/cash_session.php?action=close ──> [Backend API]
7. [Backend API] ─────> Calcula Diferencia = Contado - Esperado ─> [MySQL Database]
8. [Backend API] ─────> UPDATE cash_sessions SET status='closed' ──> [MySQL Database]
9. [CashSessionModal] > Despliega Ticket de Arqueo (✔ / DIF) ────> [Cajero (Imprime)]
Líder de Desarrollo / Arquitecto de Software
Administrador General MercariX POS