# Gratificación voluntaria

## Descripción

Tras la validación del intercambio de un objeto (mediante código), se habilita en el chat la opción para que el **propietario** envíe una gratificación voluntaria al **Finder** como gesto de agradecimiento.

## Reglas de negocio

| Regla | Detalle |
|---|---|
| Quién envía | Solo el propietario del objeto |
| Cuándo se habilita | Después de validar el intercambio |
| Importe máximo | 200,00 € |
| Importe mínimo | 0,50 € |
| Unicidad | Máximo 1 gratificación por conversación |
| Decisión del Finder | Puede aceptar o rechazar |
| Transferencia | 100 % al Stripe Connect del Finder |
| Plazo Connect | 5 días para configurar Stripe Connect tras aceptar |
| Expiración | Auto-reembolso si no se configura Connect en 5 días |

## Estados (`GratificationStatus`)

```
pending_payment → pending_acceptance → accepted → transferred
                                     ↘ rejected → (refunded)
                        accepted → expired → (refunded)
```

| Estado | Descripción |
|---|---|
| `pending_payment` | PI creado, esperando confirmación de Stripe |
| `pending_acceptance` | Pago confirmado, esperando decisión del Finder |
| `accepted` | Finder aceptó, pendiente de transferencia a Connect |
| `rejected` | Finder rechazó, se reembolsa automáticamente |
| `transferred` | Fondos transferidos al Connect del Finder |
| `refunded` | Reembolso ejecutado (por rechazo o fallo) |
| `expired` | Aceptada pero Connect no configurado en 5 días |

## Arquitectura

### Backend (Laravel)

| Archivo | Propósito |
|---|---|
| `app/Enum/GratificationStatus.php` | Enum con los 7 estados y transiciones |
| `app/Models/Gratification.php` | Modelo Eloquent (`MAX_AMOUNT=200`, `EXPIRATION_DAYS=5`) |
| `database/migrations/2026_02_24_124908_create_gratifications_table.php` | Migración |
| `database/factories/GratificationFactory.php` | Factory con state methods |
| `app/Services/GratificationService.php` | Lógica de negocio (crear, confirmar, aceptar, rechazar, transferir, reembolsar, expirar) |
| `app/Http/Controllers/App/GratificationController.php` | Endpoints API para la app |
| `app/Console/Commands/ExpireGratifications.php` | Comando `gratifications:expire` (hourly) |
| `app/Models/Conversation.php` | Relación `gratification()` HasOne añadida |
| `app/Http/Controllers/Api/ConversationController.php` | `show()` incluye datos de gratificación |
| `lang/{en,es,ca,pt,de,fr,it}/gratification.php` | Traducciones backend |
| `tests/Feature/GratificationTest.php` | 17 tests, 63 assertions |

### Endpoints API (app)

Prefix: `/gratification`

| Método | Ruta | Acción |
|---|---|---|
| `POST` | `{conversationId}/send` | Crear gratificación + PI de Stripe |
| `POST` | `{conversationId}/confirm` | Confirmar pago completado |
| `POST` | `{gratificationId}/accept` | Finder acepta |
| `POST` | `{gratificationId}/reject` | Finder rechaza |
| `POST` | `{gratificationId}/retry-transfer` | Reintentar transferencia tras Connect |
| `GET` | `{conversationId}/status` | Estado actual (+ `can_send`, `is_owner`) |

### App (Ionic/Angular)

| Archivo | Propósito |
|---|---|
| `src/app/services/api/gratification.service.ts` | Servicio HTTP con interfaces tipadas |
| `src/app/components/chat/gratification-banner/gratification-banner.component.ts` | Componente del banner |
| `src/app/components/chat/gratification-banner/gratification-banner.component.html` | Template con estados |
| `src/app/components/chat/gratification-banner/gratification-banner.component.scss` | Estilos |
| `src/app/components/components.module.ts` | Registro del componente |
| `src/app/views/chat/messages/messages.page.html` | Integración tras chip de validación |
| `src/app/views/chat/messages/messages.page.ts` | Handler `onGratificationChanged` |
| `src/assets/i18n/{en,es,ca,pt,de,fr,it}.json` | Traducciones GRATIFICATION.* |

### Panel (Angular/PrimeNG)

| Archivo | Propósito |
|---|---|
| `src/app/pages/conversation-detail/conversation-detail.component.ts` | Extrae `gratification` de la respuesta |
| `src/app/pages/conversation-detail/conversation-detail.component.html` | Sección visual con estado, importe, fechas |
| `src/app/pages/conversation-detail/conversation-detail.component.scss` | Estilos + badges de estado |

## Flujo de Stripe

1. **Propietario envía**: Backend crea `PaymentIntent` (manual capture) → App muestra PaymentSheet
2. **Pago confirmado**: Backend captura el PI → estado pasa a `pending_acceptance`
3. **Finder acepta**: Si tiene Connect onboarded → transferencia directa. Si no → estado `accepted`, 5 días para configurar
4. **Finder rechaza**: Reembolso automático del PI
5. **Expiración**: Comando `gratifications:expire` (hourly) reembolsa aceptadas sin Connect pasados 5 días

## Tests

```bash
php artisan test --filter=GratificationTest
# 17 tests, 63 assertions — ALL PASSING
```
