# REPORTE-SWEEP-PERMISOS — New-Unity ERP
**Fecha:** 22/07/2026
**Alcance:** Middleware granular de permisos (Spatie) en todos los módulos
**Referencia:** `app/Modules/Sales/Routes/web.php` v2.0

---

## 1. Archivos Modificados

| Archivo | Versión anterior | Versión nueva |
|---|---|---|
| `app/Modules/Warehouse/Routes/web.php` | v1.8 | v2.0 |
| `app/Modules/Purchases/Routes/web.php` | v1.5 | v2.0 |
| `app/Modules/Deliveries/Routes/web.php` | v1.1 | v2.0 |
| `app/Modules/Billing/Routes/web.php` | v2.0 | v2.1 |
| `resources/views/layouts/partials/unity-navigation.blade.php` | v2.3 | v2.4 |

**Sin cambios (ya estaban correctos):**
- `app/Modules/Admin/Routes/web.php` v1.2 — users/roles CRUD guards completos ✓
- `app/Modules/Finance/Routes/web.php` v1.1 — finance.access + CRUD guards ✓
- `app/Modules/Products/Routes/web.php` v1.3 — products.access + CRUD guards ✓
- `app/Modules/Sales/Routes/web.php` v2.0 — referencia, ya correcto ✓
- `app/Modules/Production/Routes/web.php` v1.2 — módulo dormido, solo ruta /test ✓

---

## 2. Tabla Ruta → Permiso por Módulo

### WAREHOUSE (`/warehouse/*`)

| Ruta | Método | Permiso(s) |
|---|---|---|
| `/warehouse/` (dashboard) | GET | `warehouse.access` |
| `/warehouse/warehouses/` | GET | `warehouse.access` |
| `/warehouse/warehouses/create` | GET | `warehouse.access` + `warehouse.create` |
| `/warehouse/warehouses/` | POST | `warehouse.access` + `warehouse.create` |
| `/warehouse/warehouses/{w}/edit` | GET | `warehouse.access` + `warehouse.edit` |
| `/warehouse/warehouses/{w}` | PUT | `warehouse.access` + `warehouse.edit` |
| `/warehouse/warehouses/{w}` | DELETE | `warehouse.access` + `warehouse.delete` |
| `/warehouse/warehouses/{w}` | GET | `warehouse.access` |
| `/warehouse/locations/` | GET | `warehouse.access` |
| `/warehouse/locations/create` | GET | `warehouse.access` + `warehouse.create` |
| `/warehouse/locations/` | POST | `warehouse.access` + `warehouse.create` |
| `/warehouse/locations/{l}/edit` | GET | `warehouse.access` + `warehouse.edit` |
| `/warehouse/locations/{l}` | PUT | `warehouse.access` + `warehouse.edit` |
| `/warehouse/locations/{l}` | DELETE | `warehouse.access` + `warehouse.delete` |
| `/warehouse/inventory/` | GET | `warehouse.access` |
| `/warehouse/inventory/stock-overview` | GET | `warehouse.access` + `warehouse.reports` |
| `/warehouse/inventory/kardex/{id}` | GET | `warehouse.access` + `warehouse.reports` |
| `/warehouse/inventory/check-stock` | GET | `warehouse.access` + `warehouse.reports` |
| `/warehouse/inventory/dispose` | POST | `warehouse.access` + `warehouse.dispose` |
| `/warehouse/inventory/free-bins-tr` | GET | `warehouse.access` + `warehouse.dispose` |
| `/warehouse/inventory/check-original-lot` | GET | `warehouse.access` + `warehouse.dispose` |
| `/warehouse/inventory/disposal/{order}/print` | GET | `warehouse.access` + `warehouse.dispose` |
| `/warehouse/inventory/entry` | POST | `warehouse.access` + `warehouse.create` |
| `/warehouse/inventory/adjust` | POST | `warehouse.access` + `warehouse.edit` + `warehouse.adjust` |
| `/warehouse/inventory/adjust-reason` | POST | `warehouse.access` + `warehouse.edit` + `warehouse.adjust` |
| `/warehouse/inventory/thresholds` | POST | `warehouse.access` + `warehouse.edit` |
| `/warehouse/racks/` (todos los subpath) | * | `warehouse.access` + `warehouse.racks` |
| `/warehouse/racks/` | POST | `warehouse.access` + `warehouse.racks` + `warehouse.create` |
| `/warehouse/racks/{r}` | PUT | `warehouse.access` + `warehouse.racks` + `warehouse.edit` |
| `/warehouse/receptions/` | GET | `warehouse.access` |
| `/warehouse/receptions/{r}` | GET | `warehouse.access` |
| `/warehouse/receptions/create` | GET | `warehouse.access` + `warehouse.receive` |
| `/warehouse/receptions/` | POST | `warehouse.access` + `warehouse.receive` |
| `/warehouse/receptions/search-po` | POST | `warehouse.access` + `warehouse.receive` |
| `/warehouse/receptions/next-lot` | GET | `warehouse.access` + `warehouse.receive` |
| `/warehouse/receptions/load-po` | POST | `warehouse.access` + `warehouse.receive` |
| `/warehouse/receptions/{r}/confirm-label` | POST | `warehouse.access` + `warehouse.receive` |
| `/warehouse/picking/` | GET | `warehouse.access` |
| `/warehouse/picking/{p}` | GET | `warehouse.access` |
| `/warehouse/picking/pending-count` | GET | `warehouse.access` |
| `/warehouse/picking/generate-for-order` | POST | `warehouse.access` + `warehouse.picking` |
| `/warehouse/picking/{p}/confirm` | POST | `warehouse.access` + `warehouse.picking` |
| `/warehouse/proposals/` | GET | `warehouse.access` |
| `/warehouse/proposals/{p}/approve` | POST | `warehouse.access` + `warehouse.edit` |
| `/warehouse/proposals/{p}/reject` | POST | `warehouse.access` + `warehouse.edit` |
| `/warehouse/alerts/` | GET | `warehouse.access` |
| `/warehouse/alerts/{a}/acknowledge` | POST | `warehouse.access` + `warehouse.edit` |
| `/warehouse/alerts/{a}/resolve` | POST | `warehouse.access` + `warehouse.edit` |
| `/warehouse/transfers/` | GET | `warehouse.access` |
| `/warehouse/transfers/{t}` | GET | `warehouse.access` |
| `/warehouse/transfers/destination-bins` | GET | `warehouse.access` |
| `/warehouse/transfers/create` | GET | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/transfers/` | POST | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/transfers/{t}/confirm` | POST | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/transfers/{t}/dispatch` | POST | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/transfers/{t}/receive` | POST | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/transfers/{t}/cancel` | POST | `warehouse.access` + `warehouse.transfer` |
| `/warehouse/traceability/*` | GET | `warehouse.access` + `warehouse.reports` |

### PURCHASES (`/purchases/*`)

| Ruta | Método | Permiso(s) |
|---|---|---|
| `/purchases/suppliers/` | GET | `suppliers.access` |
| `/purchases/suppliers/{s}` | GET | `suppliers.access` |
| `/purchases/suppliers/template` | GET | `suppliers.access` |
| `/purchases/suppliers/create` | GET | `suppliers.access` + `suppliers.create` |
| `/purchases/suppliers/` | POST | `suppliers.access` + `suppliers.create` |
| `/purchases/suppliers/import` | POST | `suppliers.access` + `suppliers.create` |
| `/purchases/suppliers/{s}/edit` | GET | `suppliers.access` + `suppliers.edit` |
| `/purchases/suppliers/{s}` | PUT | `suppliers.access` + `suppliers.edit` |
| `/purchases/suppliers/{s}` | DELETE | `suppliers.access` + `suppliers.delete` |
| `/purchases/orders/` | GET | `purchases.access` |
| `/purchases/orders/{o}` | GET | `purchases.access` |
| `/purchases/orders/{o}/pdf` | GET | `purchases.access` |
| `/purchases/orders/ajax/search-products` | GET | `purchases.access` |
| `/purchases/orders/create` | GET | `purchases.access` + `purchases.create` |
| `/purchases/orders/` | POST | `purchases.access` + `purchases.create` |
| `/purchases/orders/{o}/status` | POST | `purchases.access` + `purchases.edit` |
| `/purchases/orders/{o}/send` | POST | `purchases.access` + `purchases.edit` |
| `/purchases/costs/` | GET | `costs.access` |
| `/purchases/costs/history` | GET | `costs.access` |
| `/purchases/costs/product-cost` | GET | `costs.access` |
| `/purchases/costs/check-existing/{id}` | GET | `costs.access` |
| `/purchases/costs/create` | GET | `costs.access` + `costs.create` |
| `/purchases/costs/` | POST | `costs.access` + `costs.create` |
| `/purchases/costs/{c}/edit` | GET | `costs.access` + `costs.edit` |
| `/purchases/costs/{c}` | PUT | `costs.access` + `costs.edit` |
| `/purchases/rfq/` | GET | `purchases.access` |
| `/purchases/rfq/{r}` | GET | `purchases.access` |
| `/purchases/rfq/{r}/quotes/{q}` | GET | `purchases.access` |
| `/purchases/rfq/ajax/product-info/{p}` | GET | `purchases.access` |
| `/purchases/rfq/create` | GET | `purchases.access` + `purchases.create` |
| `/purchases/rfq/` | POST | `purchases.access` + `purchases.create` |
| `/purchases/rfq/{r}/quotes` | POST | `purchases.access` + `purchases.create` |
| `/purchases/rfq/{r}/edit` | GET | `purchases.access` + `purchases.edit` |
| `/purchases/rfq/{r}` | PUT | `purchases.access` + `purchases.edit` |
| `/purchases/rfq/{r}/quotes/{q}` | PUT | `purchases.access` + `purchases.edit` |
| `/purchases/rfq/{r}/award` | POST | `purchases.access` + `purchases.edit` |
| `/purchases/rfq/{r}/suppliers` | POST | `purchases.access` + `purchases.edit` |
| `/purchases/rfq/{r}` | DELETE | `purchases.access` + `purchases.delete` |
| `/purchases/rfq/{r}/quotes/{q}` | DELETE | `purchases.access` + `purchases.delete` |

### DELIVERIES (`/deliveries/*`)

| Ruta | Método | Permiso(s) |
|---|---|---|
| Todas las rutas del módulo | * | `warehouse.picking` |

### BILLING — SAT Catalogs (`/billing/sat-catalogs/*`)

| Acción | Método | Permiso(s) |
|---|---|---|
| `{catalog}/index` | GET | `billing.access` + `billing.configured` |
| `{catalog}/create` (form) | GET | `billing.access` + `billing.configured` |
| `{catalog}/edit` (form) | GET | `billing.access` + `billing.configured` |
| `{catalog}/store` | POST | `billing.access` + `billing.configured` + `billing.create` |
| `{catalog}/import` | POST | `billing.access` + `billing.configured` + `billing.create` |
| `{catalog}/update` | PUT/PATCH | `billing.access` + `billing.configured` + `billing.edit` |
| `{catalog}/destroy` | DELETE | `billing.access` + `billing.configured` + `billing.delete` |
| `download/template/{file}` | GET | `billing.access` + `billing.configured` |

*Catálogos: unity-keys, operators, prod-serv, payment-ways, payment-methods, relation-types, cfdi-use, fiscal-regime*

---

## 3. Hallazgos Pendientes de Decisión

### H-01 — Deliveries sin permisos propios
**Descripción:** El módulo Deliveries no tiene permisos `deliveries.*` en ningún seeder. Se mapeó a `warehouse.picking` como indicaron las instrucciones.
**Impacto:** Los usuarios con `warehouse.picking` pueden ver y operar todas las entregas. No existe granularidad interna (ver vs. despachar vs. cancelar).
**Propuesta:** Crear permisos propios en un seeder nuevo:
```php
'deliveries.access', 'deliveries.view',
'deliveries.confirm',   // confirmar entrega
'deliveries.dispatch',  // despachar
'deliveries.cancel',    // cancelar
```
**Acción requerida:** Crear `DeliveriesPermissionsSeeder.php` y asignarlo a roles.

---

### H-02 — Ruta duplicada en Picking (v1.8)
**Descripción:** En `web.php` v1.8 existían dos `POST /warehouse/picking/generate` con controladores distintos:
- `WarehouseLocationController::generateStore` (nombre: `generate.store`)
- `WarehousePickingController::generateForOrder` (nombre: `generate`, sobreescribía al anterior)

En v2.0 se resolvió el conflicto renombrando la segunda ruta a `POST /generate-for-order` (nombre: `warehouse.picking.generate-for-order`).
**Riesgo:** Si alguna vista/JS llama a `route('warehouse.picking.generate')` por POST o hace `POST /warehouse/picking/generate`, la petición ahora cae en `WarehouseLocationController::generateStore` en lugar de `generateForOrder`.
**Acción requerida:** Verificar en vistas/JS si se usa la ruta de generación de picking y actualizar la URL/nombre si es necesario.

---

### H-03 — Inventory entry vs. warehouse.receive
**Descripción:** La ruta `POST /warehouse/inventory/entry` (entrada directa de inventario) está protegida por `warehouse.create`. Semánticamente podría pertenecer a `warehouse.receive`, pero la entrada directa es diferente al flujo GR Wizard.
**Estado:** Dejado como `warehouse.create`. Si la entrada directa debe restringirse a solo el personal de recepción, cambiar a `warehouse.receive`.

---

### H-04 — Proposals MRP sin permiso funcional específico
**Descripción:** Las rutas de aprobación/rechazo de propuestas MRP usan `warehouse.edit`. No existe un permiso `warehouse.proposals` o `warehouse.mrp`.
**Estado:** Dejado como `warehouse.edit` (comportamiento anterior). Sin cambios porque no existe permiso específico en el seeder.
**Propuesta:** Considerar agregar `warehouse.mrp` o `warehouse.approve` al seeder si se desea granularidad.

---

### H-05 — SMTP Config sin permiso propio
**Descripción:** Las rutas de configuración SMTP (`/admin/smtp-config`) están protegidas solo por `users.access`. Cualquier usuario con acceso a la sección de usuarios puede ver/modificar la config SMTP.
**Status:** No modificado (las rutas de setup/admin caen fuera del alcance de CRUD granular por instrucciones). Reportado para decisión.
**Propuesta:** Agregar permiso `smtp.manage` al AdminPermissionsSeeder y asignarlo solo a roles Sistemas/Super Admin.

---

### H-06 — Billing Invoices — cfdixml/cfdipdf/cfdiCheckSatStatus sin guard de vista
**Descripción:** Las rutas de descarga de XML, descarga de PDF y consulta de status SAT en invoices están protegidas solo por `billing.access` (outer group), sin guard específico de `billing.view`.
**Status:** No modificado — comportamiento idéntico al v2.0. Aceptable si cualquier usuario con billing.access puede ver/descargar sus propios CFDIs.

---

## 4. Rutas que quedaron SIN protección granular adicional y por qué

| Ruta | Permiso aplicado | Razón |
|---|---|---|
| `GET /warehouse/` (dashboard) | `warehouse.access` | No existe `warehouse.dashboard` en seeder |
| `GET /warehouse/inventory/` | `warehouse.access` | Vista de listado general; misma política que otros índices |
| `GET /warehouse/proposals/` | `warehouse.access` | Vista de lista; aprobación sí tiene `warehouse.edit` |
| `GET /warehouse/alerts/` | `warehouse.access` | Vista de lista; acciones sí tienen `warehouse.edit` |
| `GET /warehouse/transfers/` + `show` + `destination-bins` | `warehouse.access` | Vistas de solo lectura; escritura sí tiene `warehouse.transfer` |
| `GET /warehouse/picking/index` + `show` + `pending-count` | `warehouse.access` | Vistas de solo lectura; acciones sí tienen `warehouse.picking` |
| `GET /warehouse/receptions/index` + `show` | `warehouse.access` | Vistas de solo lectura; operaciones GR tienen `warehouse.receive` |
| `GET /purchases/suppliers/template` | `suppliers.access` | Descarga de plantilla = lectura |
| `GET /purchases/orders/{o}/pdf` | `purchases.access` | PDF de PO = lectura |
| `billing/sat-catalogs/.../create` (GET form) | `billing.access` | Formulario de creación sin guard extra; el POST sí tiene `billing.create` |
| `billing/sat-catalogs/download/template/{f}` | `billing.access` | Descarga de plantilla = lectura |
| `GET /invoices/cfdixml` + `cfdipdf` | `billing.access` | Descarga de documentos propios = lectura |
| `Production /test` | `production.access` | Módulo dormido, ruta de verificación temporal |
