# Editar clientes desde la PWA — Diseño

**Fecha:** 2026-07-18
**Estado:** Aprobado (pendiente de plan de implementación)

## Objetivo

Permitir **editar** un cliente existente desde la PWA del cobrador. Hoy la PWA
puede **listar**, **ver el detalle** y **crear** clientes, pero no editarlos: no
existe endpoint `PUT /clients/{id}` ni vista de edición.

## Decisiones (acordadas)

- **Campos editables:** todos los del formulario de creación —
  `name`, `identification` (cédula), `phone`, `email` y la **dirección primaria**
  (`state` / `city` / `address_line_1`). La cédula **sí** se edita, con validación
  de unicidad por empresa que **ignora al propio cliente**.
- **No** entran en alcance `is_active` ni `preferred_payment_method` (no están en el
  formulario de creación; se gestionan en otro lugar).
- **Permiso:** admin, supervisor y cobrador (igual que crear), siempre **por empresa**.
- **Offline:** **solo-online** (igual que crear). Además, tras un guardado exitoso se
  **actualiza IndexedDB** (`db.clients`) para que la lista/detalle reflejen el cambio
  de inmediato sin esperar al próximo sync.
- **Enfoque de UI:** extraer un componente **`ClientForm.vue`** compartido por crear y
  editar (DRY).

## Alcance

### Backend

1. **Ruta:** `PUT /api/pwa/clients/{id}` → `ClientController@update`, dentro del mismo
   grupo autenticado (Sanctum) que el resto de `/pwa/clients`.

2. **`UpdateClientRequest`** (nuevo, `app/Http/Requests/Pwa/`): mismas reglas que
   `StoreClientRequest`, con una diferencia clave —
   `identification` única por empresa **ignorando el id actual**:
   `Rule::unique('clients','identification')->where('company_id',$companyId)->ignore($clientId)`.
   `authorize()` devuelve `true` (la autorización real la hace el controlador).

3. **Permiso `canEditClients`** (nuevo en `RoleAwareQueries`): `in_array($role,
   ['admin','supervisor','collector'])` — espejo de `canCreateClients`.

4. **Alcance/visibilidad:** el cliente objetivo se resuelve con **la misma regla de
   visibilidad que `show()`**:
   - admin/supervisor: cualquier cliente de su empresa;
   - collector: clientes con créditos asignados a él **o** creados por él.
   Si el cliente no es visible/no existe → **404**. Rol no permitido → **403**.

5. **`update()`** (transacción):
   - Actualiza `name`, `identification`, `phone`, `email`.
   - **Upsert de la dirección primaria:** si el cliente ya tiene `primaryAddress`, se
     actualiza (`address_line_1`, `state`, `city`); si no, se **crea** una con
     `is_primary = true` (solo si llega algún campo de dirección).
   - **Sin** `runGuardedCreate` ni chequeo de cupo (no se crea un cliente nuevo).
   - Devuelve el cliente actualizado (incluyendo los campos estructurados de dirección).

6. **Extender `show()`**: además del `address` formateado que ya devuelve, incluir los
   campos **estructurados** `state`, `city`, `address_line_1` (desde `primaryAddress`)
   para poder **precargar** los selects de departamento/ciudad y el textarea de
   dirección en el formulario de edición. El `formatted_address` se conserva para el
   detalle.

### Frontend

1. **`ClientForm.vue`** (nuevo, `resources/js/pwa/components/`): se extrae de
   `ClientCreateView` — campos (nombre, cédula, teléfono, email, select departamento,
   select ciudad, textarea dirección), validación (`isFormValid`), y la carga de
   departamentos/ciudades. Props: datos iniciales, `mode` (`create` | `edit`), estado
   `submitting` y `isOnline`; emite `submit` con el payload. **Sin cambios de
   comportamiento** para crear.

2. **`ClientCreateView`**: pasa a usar `ClientForm` en modo `create` (equivalente al
   actual).

3. **`ClientEditView`** (nuevo, ruta `/pwa/clients/:id/edit`, name `client-edit`):
   - Al montar, hace `GET /pwa/clients/:id` (`show`) y **precarga** `ClientForm`.
   - Envía `PUT /pwa/clients/:id`.
   - Al éxito: toast, **actualiza `db.clients`** con el registro editado (mismo shape que
     usa la lista), y navega de vuelta al detalle (`/pwa/clients/:id`).
   - **Solo-online:** botón deshabilitado sin conexión, mismo aviso ámbar que crear.
   - Manejo de errores 422 (validación) / 403 / 404 / genérico, como en crear.

4. **`ClientDetailView`**: botón **"Editar"** (visible si `authStore.canEditClients`)
   que enruta a `client-edit`.

5. **`auth store`**: agregar `canEditClients` computed
   (`permissions.can_edit_clients ?? ['admin','supervisor','collector'].includes(role)`),
   espejo de `canCreateClients`.

6. **Router:** registrar `/pwa/clients/:id/edit`.

7. **IndexedDB:** tras el `PUT` exitoso, `db.clients.put(registroActualizado)` con el
   mismo shape que consume `ClientsView` (id, name, identification, phone, … — a
   confirmar contra la lista durante la implementación), para consistencia offline
   inmediata.

## Flujo de datos

1. Detalle del cliente → botón **Editar** → `/pwa/clients/:id/edit`.
2. `ClientEditView` hace `GET show` → precarga `ClientForm` (incluida la dirección
   estructurada).
3. Usuario edita → `PUT /pwa/clients/:id`.
4. Backend valida (cédula única ignorando al propio), autoriza (rol + visibilidad por
   empresa), actualiza cliente + dirección primaria en transacción, devuelve el cliente.
5. Frontend: toast → `db.clients.put(...)` → navega al detalle (que re-consulta online).

## Seguridad / multi-tenant

- Todo acotado por `company_id`.
- Misma regla de visibilidad que `show()` para decidir a qué cliente puede llegar cada
  rol (el cobrador no edita clientes ajenos a su alcance → 404).
- Unicidad de cédula ignora al propio cliente (permite conservarla; rechaza duplicar la
  de otro).
- 403 si el rol no puede editar; 404 si el cliente no es visible.

## Testing

**Backend (feature tests, `tests/Feature/Pwa/`):**
- admin, supervisor y cobrador pueden editar un cliente visible (200 + cambios
  persistidos, incl. dirección primaria upsert).
- cobrador **no** puede editar un cliente fuera de su alcance → 404.
- cross-company bloqueado → 404.
- unicidad de cédula: conservar la propia cédula pasa; usar la cédula de otro cliente de
  la empresa → 422.
- validación de campos requeridos → 422.
- (opcional) un rol sin permiso → 403 — hoy los tres roles PWA pueden, así que este caso
  aplica solo si más adelante se restringe.

**Frontend:** el repo no tiene infraestructura de tests JS (sin Vitest/Jest). Se verifica
con `npm run build` (sin errores) + revisión en navegador (precarga correcta, guardado,
actualización de la lista offline, botón oculto para roles sin permiso si aplicara).

## Fuera de alcance

- Editar `is_active` / `preferred_payment_method` desde la PWA.
- Edición **offline** con cola de sincronización (crear es solo-online; editar mantiene
  la misma política).
- Múltiples direcciones por cliente (se gestiona solo la **primaria**, como en crear).
- Auditoría de cambios de cliente (crear tampoco audita; se mantiene la paridad).
