`modules/customers/src/common/features` es la superficie pública del módulo `customers` para colaboración entre módulos frontend del ERP.
Estas features permiten que un consumidor:
- seleccione un cliente existente;
- cree un cliente de alta rápida;
- reciba siempre un contrato público homogéneo para aplicar el resultado en su propio formulario.
La dependencia deseada es:
```text
consumer module
│
▼
@erp/customers o @erp/customers/common
│
▼
customers/common/features
│
├── customer-selection
└── quick-create-customer
```
Un consumidor no debe resolver estos flujos importando implementación interna desde:
-`modules/customers/src/web/create`
-`modules/customers/src/web/update`
-`modules/customers/src/web/shared`
Esos directorios siguen siendo responsabilidad interna del módulo `customers`.
## Features públicas
### `customer-selection`
Resuelve el problema de buscar y seleccionar un cliente desde otro módulo, exponiendo un flujo reutilizable con diálogo de selección y un contrato público estable para devolver el cliente elegido.
API pública real exportada por `modules/customers/src/common/features/customer-selection/index.ts`:
-`useCustomerSelectionFlow`
-`CustomerSelectionCriteria`
-`CustomerSelectionOption`
-`SelectCustomerDialog`
-`buildCustomerSelectionOption`
Responsabilidades principales:
- búsqueda y paginación de clientes;
- apertura y cierre del selector;
- transformación del resultado de listado al contrato público `CustomerSelectionOption`;
- coordinación con alta rápida cuando el consumidor usa el flow público;
- entrega del cliente seleccionado al callback del consumidor.
No pertenece a esta feature:
- construir `CreateCustomerParams`;
- conocer el formulario completo de create/update de clientes;
- invalidar cachés externas del consumidor;
- decidir qué hace el consumidor con el cliente ya seleccionado.
### `quick-create-customer`
Resuelve el problema de crear un cliente mínimo y embebible sin exponer al consumidor los detalles internos del CRUD de `customers`.
API pública real exportada por `modules/customers/src/common/features/quick-create-customer/index.ts`:
-`useQuickCreateCustomerFlow`
-`QuickCustomerCreateResult`
-`QuickCreateCustomerDialog`
Responsabilidades principales:
- formulario reducido de alta rápida;
- validación del formulario;
- apertura y cierre del diálogo;
- creación mediante la mutation propia de `customers`;
- adaptación del resultado de creación a `CustomerSelectionOption`;
- gestión de toasts, errores y estado del diálogo;
- aplicación de defaults internos y contexto opcional del consumidor.
No pertenece a esta feature:
- que el consumidor construya `CreateCustomerParams`;
- que el consumidor importe `useCustomerCreateMutation`;
- que el consumidor gestione manualmente la caché de `customers`.
## Contrato público: `CustomerSelectionOption`
`CustomerSelectionOption` representa la proyección pública que `customers` entrega a otros módulos cuando el resultado del flujo es “ya tienes un cliente seleccionable y aplicable”.
No es la entity completa del CRUD de `customers`. Es un shape orientado a integración y UI.
type QuickCustomerCreateResult = CustomerSelectionOption;
```
Eso significa que, para el consumidor, no hay dos contratos distintos:
```text
seleccionar cliente existente ───────┐
├──► CustomerSelectionOption
crear cliente rápidamente ───────────┘
```
Una vez terminada la operación, el consumidor puede usar el mismo callback para ambos casos. En el flow público actual, ese callback es `onCustomerSelected(customer)`.
## `useCustomerSelectionFlow`
`useCustomerSelectionFlow` es el punto de composición pública recomendado cuando una pantalla necesita:
- seleccionar un cliente existente;
- abrir alta rápida desde el selector;
- abrir alta rápida directamente desde la pantalla;
→ sigue construyendo, validando y ejecutando la creación
```
El consumidor no debe construir `CreateCustomerParams`.
### Validación, errores y toasts
La responsabilidad de validación y feedback está dentro de `quick-create-customer`:
-`QuickCustomerCreateFormSchema` valida el formulario;
-`useQuickCreateCustomerDialogController` aplica errores de validación al form;
- la feature muestra `showSuccessToast`, `showWarningToast` y `showErrorToast`;
- el diálogo mantiene `submitError` y el estado `isSubmitting`.
Por tanto, un consumidor normal no debería duplicar:
-`try/catch` del submit;
- toasts de éxito/error de creación;
-`setError` sobre el formulario rápido.
### Caché
La creación usa `useCustomerCreateMutation()` desde el módulo `customers`.
La sincronización de React Query y su estrategia de caché siguen siendo responsabilidad de `customers`. El consumidor no debe invalidar manualmente queries de `customers` tras una creación rápida salvo un caso excepcional y explícitamente justificado.
- el page controller compone `useCustomerSelectionFlow`;
- la pantalla usa `selectCustomerCtrl.openQuickCreateDialog` para el botón principal `Nuevo cliente`;
-`SelectCustomerDialog` usa `selectCustomerCtrl.openQuickCreateFromSelection` para `Nuevo cliente` dentro del selector;
- ambos caminos convergen en `updateCtrl.setCustomer(customer)`.
## Rehidratación y snapshots externos
`CustomerSelectionOption` es el contrato ideal que `customers` entrega a consumidores.
Eso no implica que cualquier otro recurso del ERP tenga que persistir exactamente el mismo shape. Por ejemplo, una proforma puede contener un snapshot suficiente para representar a su cliente, pero no necesariamente todos los campos disponibles en `CustomerSelectionOption`.
La integración correcta consiste en:
- usar `CustomerSelectionOption` cuando el dato proviene del flujo público de `customers`;
- permitir que recursos externos reconstruyan su propio resumen cuando trabajan con snapshots parciales.
## Qué debe importar un consumidor
Imports recomendados:
```ts
import { useCustomerSelectionFlow } from "@erp/customers/common";
import type { CustomerSelectionOption } from "@erp/customers";
import { QuickCreateCustomerDialog, SelectCustomerDialog } from "@erp/customers";
```
La ruta concreta puede variar según el barrel elegido, pero debe salir de la superficie pública exportada por `@erp/customers` o `@erp/customers/common`.
## Qué no debe importar un consumidor
No debe depender directamente de piezas internas del CRUD como:
-`CreateCustomerParams`
-`CustomerCreateForm`
-`useCustomerCreateMutation`
-`buildCreateCustomerParams`
- componentes o hooks desde `modules/customers/src/web/create/*`
- detalles internos de `modules/customers/src/web/shared/*`
## Respuestas rápidas de contrato
1.`customer-selection` resuelve búsqueda, selección y entrega homogénea de cliente.
2.`quick-create-customer` resuelve alta mínima embebible sin exponer el CRUD interno.
3. La API pública real está definida por los barrels de cada feature, no por sus internals.
4. El consumidor debe importar desde `@erp/customers` o `@erp/customers/common`.
5. No debe importar internals de `web/create`, `web/update` o `web/shared`.
6.`CustomerSelectionOption` es la proyección pública reutilizable de cliente seleccionado.
7.`QuickCustomerCreateResult` converge en el mismo contrato para no bifurcar la integración.
8.`openQuickCreateDialog` es apertura directa; `openQuickCreateFromSelection` preserva el retorno al selector.
9. La cancelación y la reapertura del selector las gestiona el flow de `customers`.
10. La creación, validación, errores y caché pertenecen a `customers`.
11. El consumidor integra el resultado aplicando `CustomerSelectionOption` a su propio caso de uso.
12.`proformas/update` lo hace actualmente con `updateCtrl.setCustomer(customer)`.