# Entrada Simplificada: toggle único + gastos/socios/promesa — Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Hacer que el "modo simplificado" dependa de **un solo toggle maestro** (fuera los toggles por área) y **aplicarlo** también en Registrar Gasto, Transacción de Socio y el Monto Prometido de la visita "no paga hoy".

**Architecture:** Backend — `isSimplifiedInputEnabled()` pasa a ser **master-only** (ignora el contexto); el payload de settings expone `enabled/credit_enabled/payment_enabled` todos = maestro (baja fricción: crédito/pago no cambian); `update()` deja de manejar flags por área; los 3 endpoints nuevos convierten el monto crudo → real siguiendo el patrón de crédito (flag `is_simplified_amount` + `convertSimplifiedToReal`). Frontend — se amplía el validador de `context` de `SimplifiedAmountInput`, se cablean los 3 formularios (patrón `CreditCreateView`), y se quitan los 2 toggles por área de `CompanySettingsView`.

**Tech Stack:** Laravel 13 (PHPUnit, FormRequests), Vue 3 `<script setup>` (Pinia), Tailwind v4, Vite.

**Spec:** `docs/superpowers/specs/2026-08-01-simplified-input-expand-design.md`

**Gotchas (memoria):**
- Tests comparten la BD dev `credify`, seguros por `DatabaseTransactions`. Patrón de test PWA: `Company/User/Plan/Subscription` factories + `$user->assignRole('admin')` + `Sanctum::actingAs($user->fresh())` + `$this->postJson('/api/pwa/...')`. Ver [[credify-test-db]].
- **PHPStan level 5** sobre `app/` antes de push. Ver [[credify-ci-phpstan-preflight]].
- Sin tests JS de la PWA → `npm run build` + revisión + validación en dispositivo.
- Commits desde WSL; NO stage `.claude/`. Deploy **full** (assets + backend). Ver [[credify-prod-vm]].
- Patrón de conversión (crédito, `StoreCreditRequest::prepareForValidation`): `if ($this->boolean('is_simplified_amount') && $this->amount) { $settings = CompanyFinancialSettings::forCompany($user->company_id); if ($settings->isSimplifiedInputEnabled(...)) { $this->merge(['amount' => $settings->convertSimplifiedToReal((float) $this->amount)]); } }`.

---

## File Structure

```
BACKEND
  app/Models/CompanyFinancialSettings.php                MODIFY  isSimplifiedInputEnabled() → master-only
  app/Http/Controllers/Api/Pwa/SettingsController.php     MODIFY  payload (todos=maestro) + update() (fuera flags área) + simplifiedInput()
  app/Http/Controllers/Api/Pwa/ExpenseController.php      MODIFY  store(): convertir + aceptar flags
  app/Http/Controllers/Api/Pwa/PartnerController.php      MODIFY  storeTransaction(): convertir (antes del balance check)
  app/Http/Requests/Pwa/StoreCollectionVisitRequest.php  MODIFY  prepareForValidation() para promised_amount
  tests/Feature/Pwa/SimplifiedInputExpandTest.php         CREATE  cobertura de los 4 (+ master gating)
FRONTEND (resources/js/pwa/)
  components/forms/SimplifiedAmountInput.vue              MODIFY  validador context + isSimplified master
  views/ExpenseCreateView.vue                            MODIFY  usar SimplifiedAmountInput (expense)
  views/PartnerTransactionView.vue                       MODIFY  usar SimplifiedAmountInput (partner)
  components/collections/NoPaymentModal.vue               MODIFY  usar SimplifiedAmountInput (promise, opcional)
  views/CompanySettingsView.vue                          MODIFY  quitar 2 toggles + vars + helper text
CHANGELOG.md                                              MODIFY
```

---

### Task 1: Backend — gating master-only (modelo + SettingsController) [TDD]

**Files:**
- Modify: `app/Models/CompanyFinancialSettings.php:466-482`
- Modify: `app/Http/Controllers/Api/Pwa/SettingsController.php` (payload 45-52, `update()` 98-183, `simplifiedInput()` 190-207)
- Test: `tests/Feature/Pwa/SimplifiedInputExpandTest.php` (nuevo)

- [ ] **Step 1: Test del modelo (master-only, ignora contexto)**

Crea `tests/Feature/Pwa/SimplifiedInputExpandTest.php` con este primer test:

```php
<?php

namespace Tests\Feature\Pwa;

use App\Models\CompanyFinancialSettings;
use Tests\TestCase;

class SimplifiedInputExpandTest extends TestCase
{
    public function test_simplified_input_gating_is_master_only_ignoring_context(): void
    {
        $on = new CompanyFinancialSettings([
            'simplified_input_enabled' => true,
            'simplified_input_multiplier' => 1000,
            'simplified_input_contexts' => [],
        ]);
        $this->assertTrue($on->isSimplifiedInputEnabled());
        $this->assertTrue($on->isSimplifiedInputEnabled('pwa_credit_create'));
        $this->assertTrue($on->isSimplifiedInputEnabled('pwa_expense_create'));

        $off = new CompanyFinancialSettings(['simplified_input_enabled' => false]);
        $this->assertFalse($off->isSimplifiedInputEnabled());
        $this->assertFalse($off->isSimplifiedInputEnabled('pwa_credit_create'));
    }
}
```

- [ ] **Step 2: Correr → falla**

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=SimplifiedInputExpandTest 2>&1 | tail -8"
```
Expected: FAIL (hoy `isSimplifiedInputEnabled('pwa_credit_create')` mira el array de contextos, que está vacío → false).

- [ ] **Step 3: Modelo master-only**

En `CompanyFinancialSettings.php`, reemplaza el cuerpo de `isSimplifiedInputEnabled()` (466-482) por:

```php
    /**
     * Modo simplificado: gating por el toggle MAESTRO únicamente.
     * El parámetro $context se conserva por compatibilidad de firma pero se ignora
     * (antes gateaba por simplified_input_contexts; ahora todo depende del maestro).
     */
    public function isSimplifiedInputEnabled(?string $context = null): bool
    {
        return (bool) $this->simplified_input_enabled;
    }
```

- [ ] **Step 4: SettingsController — payload + update + simplifiedInput**

En `SettingsController.php`:

(a) `buildSettingsPayload()` (45-52) → todos = maestro:
```php
            'simplified_input' => [
                'enabled' => $settings->isSimplifiedInputEnabled(),
                'credit_enabled' => $settings->isSimplifiedInputEnabled(),
                'payment_enabled' => $settings->isSimplifiedInputEnabled(),
                'multiplier' => $settings->simplified_input_multiplier ?? 1000,
                'require_confirm' => $settings->simplified_input_require_confirm ?? false,
            ],
```

(b) `update()` — quita las reglas `simplified_input_credit`/`simplified_input_payment` del `$request->validate([...])` y **elimina** el bloque "Reconstruir simplified_input_contexts desde flags credit/payment" (el `if (isset($validated['simplified_input_credit']) ...) { ... }`). Deja intactos los `if` de `simplified_input_enabled`/`_multiplier`/`_require_confirm`.

(c) `simplifiedInput()` (190-207) — si computa `credit_enabled`/`payment_enabled` por contexto, cámbialo para que ambos = `$settings->isSimplifiedInputEnabled()` (consistencia con el payload principal).

- [ ] **Step 5: Test de payload (feature) + correr todo**

Añade al test:
```php
    public function test_settings_payload_reports_master_for_all_simplified_flags(): void
    {
        [$admin, $company] = $this->makeAdmin();
        CompanyFinancialSettings::forCompany($company->id)->update([
            'simplified_input_enabled' => true,
            'simplified_input_contexts' => [], // sin contextos: aun así debe reportar enabled
        ]);
        \Laravel\Sanctum\Sanctum::actingAs($admin->fresh());

        $si = $this->getJson('/api/pwa/settings')->assertOk()->json('settings.simplified_input');
        $this->assertTrue($si['enabled']);
        $this->assertTrue($si['credit_enabled']);
        $this->assertTrue($si['payment_enabled']);
    }
```
Y añade el helper privado `makeAdmin()` al test (reutilizado por las tasks siguientes):
```php
    /** @return array{0: \App\Models\User, 1: \App\Models\Company} */
    private function makeAdmin(): array
    {
        \Spatie\Permission\Models\Role::firstOrCreate(['name' => 'admin', 'guard_name' => 'web']);
        $company = \App\Models\Company::factory()->create();
        $plan = \App\Models\Plan::factory()->create(['has_pwa_access' => true]);
        \App\Models\Subscription::factory()->active()->create([
            'company_id' => $company->id, 'plan_id' => $plan->id, 'ends_at' => now()->addYear(),
        ]);
        $admin = \App\Models\User::factory()->create(['company_id' => $company->id]);
        $admin->assignRole('admin');

        return [$admin, $company];
    }
```
Añade `use Illuminate\Foundation\Testing\DatabaseTransactions;` y `use DatabaseTransactions;` en la clase.

```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=SimplifiedInputExpandTest 2>&1 | tail -8"
```
Expected: PASS (2 tests).

- [ ] **Step 6: PHPStan + commit**

```bash
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/Models/CompanyFinancialSettings.php app/Http/Controllers/Api/Pwa/SettingsController.php 2>&1 | tail -4"
wsl bash -lc "cd /var/www/html/credify && git add app/Models/CompanyFinancialSettings.php app/Http/Controllers/Api/Pwa/SettingsController.php tests/Feature/Pwa/SimplifiedInputExpandTest.php && git commit -m 'feat(pwa): modo simplificado gateado solo por el toggle maestro'"
```

---

### Task 2: Backend — conversión en gastos (`ExpenseController::store`) [TDD]

`ExpenseController::store()` usa validación inline (sin FormRequest). Se convierte el monto crudo → real **antes** de `$request->validate()`, y se aceptan los flags.

**Files:**
- Modify: `app/Http/Controllers/Api/Pwa/ExpenseController.php:58-104`
- Test: `tests/Feature/Pwa/SimplifiedInputExpandTest.php`

- [ ] **Step 1: Test**

Añade al test (usa una categoría **válida** de `App\Enums\ExpenseCategory` — revísala; el ejemplo asume `'other'`, ajústalo si no existe):
```php
    public function test_expense_converts_simplified_amount_when_master_enabled(): void
    {
        [$admin, $company] = $this->makeAdmin();
        CompanyFinancialSettings::forCompany($company->id)->update([
            'simplified_input_enabled' => true, 'simplified_input_multiplier' => 1000,
        ]);
        \Laravel\Sanctum\Sanctum::actingAs($admin->fresh());

        $this->postJson('/api/pwa/expenses', [
            'amount' => 1500, 'category' => 'other', 'is_simplified_amount' => true,
        ])->assertStatus(201);

        $this->assertDatabaseHas('expenses', ['company_id' => $company->id, 'amount' => 1500000]);
    }

    public function test_expense_does_not_convert_when_master_off(): void
    {
        [$admin, $company] = $this->makeAdmin();
        CompanyFinancialSettings::forCompany($company->id)->update(['simplified_input_enabled' => false]);
        \Laravel\Sanctum\Sanctum::actingAs($admin->fresh());

        $this->postJson('/api/pwa/expenses', [
            'amount' => 1500, 'category' => 'other', 'is_simplified_amount' => true,
        ])->assertStatus(201);

        $this->assertDatabaseHas('expenses', ['company_id' => $company->id, 'amount' => 1500]);
    }
```

- [ ] **Step 2: Correr → falla** (`... --filter=SimplifiedInputExpandTest`) — el primero falla (guarda 1500, no 1.500.000).

- [ ] **Step 3: Implementar conversión**

En `ExpenseController::store()`, **al inicio del método** (antes del `$request->validate([...])`), añade:
```php
        // Modo simplificado: convertir monto crudo → real si el maestro está activo.
        // Se emite el flag desde la PWA; el backend convierte (evita doble multiplicación).
        if ($request->boolean('is_simplified_amount') && $request->filled('amount')) {
            $settings = CompanyFinancialSettings::forCompany($request->user()->company_id);
            if ($settings->isSimplifiedInputEnabled()) {
                $request->merge(['amount' => $settings->convertSimplifiedToReal((float) $request->amount)]);
            }
        }
```
Y en el array de `$request->validate([...])` añade las 2 reglas de los flags:
```php
            'is_simplified_amount' => ['nullable', 'boolean'],
            'simplified_amount_confirmed' => ['nullable', 'boolean'],
```
Asegura el `use App\Models\CompanyFinancialSettings;` arriba (si no está).

- [ ] **Step 4: Correr → pasa** (los 2 tests de gasto verdes).

- [ ] **Step 5: PHPStan + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/Http/Controllers/Api/Pwa/ExpenseController.php 2>&1 | tail -3 && git add app/Http/Controllers/Api/Pwa/ExpenseController.php tests/Feature/Pwa/SimplifiedInputExpandTest.php && git commit -m 'feat(pwa): gastos aplican modo simplificado (convierte monto crudo)'"
```

---

### Task 3: Backend — conversión en socios (`PartnerController::storeTransaction`) [TDD]

Inline (sin FormRequest). **Crítico:** la conversión debe ir **antes** del chequeo de saldo de retiro (que lee `$request->amount`).

**Files:**
- Modify: `app/Http/Controllers/Api/Pwa/PartnerController.php:74-135`
- Test: `tests/Feature/Pwa/SimplifiedInputExpandTest.php`

- [ ] **Step 1: Test**
```php
    public function test_partner_contribution_converts_simplified_amount(): void
    {
        [$admin, $company] = $this->makeAdmin();
        CompanyFinancialSettings::forCompany($company->id)->update([
            'simplified_input_enabled' => true, 'simplified_input_multiplier' => 1000,
        ]);
        $partner = \App\Models\Partner::factory()->create(['company_id' => $company->id]);
        \Laravel\Sanctum\Sanctum::actingAs($admin->fresh());

        $this->postJson("/api/pwa/partners/{$partner->id}/transaction", [
            'transaction_type' => 'contribution', 'contribution_type' => 'additional',
            'amount' => 1500, 'is_simplified_amount' => true,
        ])->assertStatus(201);

        $this->assertDatabaseHas('capital_contributions', ['company_id' => $company->id, 'amount' => 1500000]);
    }
```
(Nota: revisa que exista `Partner::factory()` y el nombre de tabla `capital_contributions`; ajusta si el modelo `CapitalContribution` usa otra tabla.)

- [ ] **Step 2: Correr → falla.**

- [ ] **Step 3: Implementar**

En `storeTransaction()`, **justo después** del check de rol admin y **antes** de `$request->validate([...])`, añade el mismo bloque de conversión:
```php
        if ($request->boolean('is_simplified_amount') && $request->filled('amount')) {
            $settings = CompanyFinancialSettings::forCompany($request->user()->company_id);
            if ($settings->isSimplifiedInputEnabled()) {
                $request->merge(['amount' => $settings->convertSimplifiedToReal((float) $request->amount)]);
            }
        }
```
Y añade al `$request->validate([...])`:
```php
            'is_simplified_amount' => ['nullable', 'boolean'],
            'simplified_amount_confirmed' => ['nullable', 'boolean'],
```
(Así el `amount` ya viene convertido cuando el chequeo de saldo de retiro lo lee.) Asegura el `use App\Models\CompanyFinancialSettings;`.

- [ ] **Step 4: Correr → pasa.**

- [ ] **Step 5: PHPStan + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/Http/Controllers/Api/Pwa/PartnerController.php 2>&1 | tail -3 && git add app/Http/Controllers/Api/Pwa/PartnerController.php tests/Feature/Pwa/SimplifiedInputExpandTest.php && git commit -m 'feat(pwa): transacciones de socio aplican modo simplificado'"
```

---

### Task 4: Backend — conversión en promesa (`StoreCollectionVisitRequest`) [TDD]

Este endpoint SÍ tiene FormRequest → se añade `prepareForValidation()` como en crédito, sobre `promised_amount` (**opcional**: solo convertir si viene).

**Files:**
- Modify: `app/Http/Requests/Pwa/StoreCollectionVisitRequest.php`
- Test: `tests/Feature/Pwa/SimplifiedInputExpandTest.php`

- [ ] **Step 1: Test**
```php
    public function test_visit_converts_simplified_promised_amount(): void
    {
        [$admin, $company] = $this->makeAdmin();
        CompanyFinancialSettings::forCompany($company->id)->update([
            'simplified_input_enabled' => true, 'simplified_input_multiplier' => 1000,
        ]);
        // Un crédito activo de la empresa para el credit_id requerido
        $credit = \App\Models\Credit::factory()->create(['company_id' => $company->id]);
        \Laravel\Sanctum\Sanctum::actingAs($admin->fresh());

        $this->postJson('/api/pwa/visits', [
            'credit_id' => $credit->id,
            'visit_type' => 'no_payment',
            'reason' => \App\Models\CollectionVisit::REASONS[0] ?? 'no_money',
            'visit_date' => now()->toDateString(),
            'promised_amount' => 1500,
            'is_simplified_amount' => true,
        ])->assertStatus(201);

        $this->assertDatabaseHas('collection_visits', ['company_id' => $company->id, 'promised_amount' => 1500000]);
    }
```
(Ajusta `Credit::factory()` / `reason` / `visit_type` a valores válidos según `CollectionVisit::VISIT_TYPES`/`REASONS`.)

- [ ] **Step 2: Correr → falla.**

- [ ] **Step 3: Implementar prepareForValidation + reglas**

En `StoreCollectionVisitRequest.php`, añade al array de `rules()`:
```php
            'is_simplified_amount' => ['nullable', 'boolean'],
            'simplified_amount_confirmed' => ['nullable', 'boolean'],
```
Y añade el método (usa `use App\Models\CompanyFinancialSettings;` arriba):
```php
    protected function prepareForValidation(): void
    {
        // Modo simplificado: convertir promised_amount crudo → real (opcional).
        if ($this->boolean('is_simplified_amount') && $this->filled('promised_amount')) {
            $settings = CompanyFinancialSettings::forCompany($this->user()->company_id);
            if ($settings->isSimplifiedInputEnabled()) {
                $this->merge([
                    'promised_amount' => $settings->convertSimplifiedToReal((float) $this->promised_amount),
                ]);
            }
        }
    }
```

- [ ] **Step 4: Correr → pasa.**

- [ ] **Step 5: PHPStan + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/Http/Requests/Pwa/StoreCollectionVisitRequest.php 2>&1 | tail -3 && git add app/Http/Requests/Pwa/StoreCollectionVisitRequest.php tests/Feature/Pwa/SimplifiedInputExpandTest.php && git commit -m 'feat(pwa): promesa de pago aplica modo simplificado (promised_amount)'"
```

---

### Task 5: Frontend — ampliar `SimplifiedAmountInput` (validador de context)

**Files:**
- Modify: `resources/js/pwa/components/forms/SimplifiedAmountInput.vue:103-108` (prop `context`) y `143-147` (`isSimplified`)

- [ ] **Step 1: Ampliar el validador del prop `context`**

Reemplaza el prop `context`:
```js
    context: {
        type: String,
        default: 'payment',
        validator: (v) => ['payment', 'credit', 'expense', 'partner', 'promise'].includes(v)
    },
```

- [ ] **Step 2: `isSimplified` gatea por el maestro**

Reemplaza la computada `isSimplified` (143-147) por:
```js
const isSimplified = computed(() => settingsStore.isSimplifiedInputEnabled)
```
(Antes ramificaba credit/payment; ahora todo depende del maestro — coherente con el gating backend.)

- [ ] **Step 3: Build + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2 && git add resources/js/pwa/components/forms/SimplifiedAmountInput.vue && git commit -m 'feat(pwa): SimplifiedAmountInput acepta expense/partner/promise y gatea por maestro'"
```

---

### Task 6: Frontend — cablear `ExpenseCreateView` (context expense)

Patrón de referencia: `CreditCreateView` (import, `<SimplifiedAmountInput>`, computeds `isSimplifiedEnabled`/`requireConfirmation`/`amountConfirmed`, gate de submit, flags en payload).

**Files:**
- Modify: `resources/js/pwa/views/ExpenseCreateView.vue`

- [ ] **Step 1: Import + store**

En el `<script setup>`, añade (si no están): `import SimplifiedAmountInput from '../components/forms/SimplifiedAmountInput.vue'` y `import { useSettingsStore } from '../stores/settings'` + `const settingsStore = useSettingsStore()`.

- [ ] **Step 2: Reemplazar el input de monto**

Reemplaza el bloque `<div class="flex items-center gap-2"><span>$</span><input v-model="form.amount" type="number" …/></div>` (20-32) por:
```vue
                <SimplifiedAmountInput
                    v-model="form.amount"
                    v-model:confirmed="amountConfirmed"
                    context="expense"
                    :min="0.01"
                    placeholder="0"
                    required
                />
```

- [ ] **Step 3: Computeds de gating + flags**

En `<script setup>` añade:
```js
const isSimplifiedEnabled = computed(() => settingsStore.isSimplifiedInputEnabled)
const requireConfirmation = computed(() => settingsStore.requireConfirm)
const amountConfirmed = ref(false)
```
En `submit()`, dentro de `expenseData`, añade los flags:
```js
        is_simplified_amount: isSimplifiedEnabled.value,
        simplified_amount_confirmed: amountConfirmed.value,
```
(Se envían tanto en el `api.post('/pwa/expenses', expenseData)` **como** en `syncStore.queueExpense(expenseData)` — es el mismo objeto → el backend convierte también al sincronizar offline.)

Y gatea el submit: al inicio de `submit()`, tras el chequeo actual, añade:
```js
    if (isSimplifiedEnabled.value && requireConfirmation.value && !amountConfirmed.value) return
```
(Verifica que `computed`/`ref` estén importados de `vue`.)

- [ ] **Step 4: Build + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2 && git add resources/js/pwa/views/ExpenseCreateView.vue && git commit -m 'feat(pwa): registrar gasto usa entrada simplificada'"
```

---

### Task 7: Frontend — cablear `PartnerTransactionView` (context partner)

**Files:**
- Modify: `resources/js/pwa/views/PartnerTransactionView.vue`

- [ ] **Step 1: Import + store** (igual que Task 6, rutas relativas `../components/...`, `../stores/settings`).

- [ ] **Step 2: Reemplazar el input de monto** (125-137) por:
```vue
                <SimplifiedAmountInput
                    v-model="form.amount"
                    v-model:confirmed="amountConfirmed"
                    context="partner"
                    :min="0.01"
                    placeholder="0"
                    required
                />
```

- [ ] **Step 3: Computeds + flags + gate**

Añade en `<script setup>`:
```js
const isSimplifiedEnabled = computed(() => settingsStore.isSimplifiedInputEnabled)
const requireConfirmation = computed(() => settingsStore.requireConfirm)
const amountConfirmed = ref(false)
```
En `submit()`, dentro del `payload`, añade:
```js
            is_simplified_amount: isSimplifiedEnabled.value,
            simplified_amount_confirmed: amountConfirmed.value,
```
Y en `isFormValid` (o al inicio de `submit()`), gatea la confirmación:
```js
    // dentro de la validación del form: si simplificado + requiere confirmación, exige amountConfirmed
```
Concretamente, al inicio de `submit()` tras `if (!isFormValid.value || !isOnline.value) return`, añade:
```js
    if (isSimplifiedEnabled.value && requireConfirmation.value && !amountConfirmed.value) return
```

- [ ] **Step 4: Build + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2 && git add resources/js/pwa/views/PartnerTransactionView.vue && git commit -m 'feat(pwa): transaccion de socio usa entrada simplificada'"
```

---

### Task 8: Frontend — cablear `NoPaymentModal` (context promise, OPCIONAL)

El monto prometido es **opcional** (bajo `showPromise`, sin `required`). Solo enviar el flag y exigir confirmación cuando haya monto.

**Files:**
- Modify: `resources/js/pwa/components/collections/NoPaymentModal.vue`

- [ ] **Step 1: Import + store** (`import SimplifiedAmountInput from '../forms/SimplifiedAmountInput.vue'`, `import { useSettingsStore } from '../../stores/settings'`, `const settingsStore = useSettingsStore()`).

- [ ] **Step 2: Reemplazar el input de monto prometido** (81-95) por (conserva el `<label>` y el wrapper):
```vue
                                <div>
                                    <label class="block text-xs text-gray-600 mb-1">Monto prometido (opcional)</label>
                                    <SimplifiedAmountInput
                                        v-model="form.promised_amount"
                                        v-model:confirmed="amountConfirmed"
                                        context="promise"
                                        :min="0"
                                        placeholder="0"
                                    />
                                </div>
```

- [ ] **Step 3: Computeds + flags (solo si hay monto)**

Añade en `<script setup>`:
```js
const isSimplifiedEnabled = computed(() => settingsStore.isSimplifiedInputEnabled)
const requireConfirmation = computed(() => settingsStore.requireConfirm)
const amountConfirmed = ref(false)
const hasPromisedAmount = computed(() => showPromise.value && !!form.promised_amount)
```
En `visitData`, cambia/añade el flag para que solo aplique cuando hay monto:
```js
        promised_amount: hasPromisedAmount.value ? form.promised_amount : null,
        is_simplified_amount: hasPromisedAmount.value && isSimplifiedEnabled.value,
        simplified_amount_confirmed: amountConfirmed.value,
```
(Se envía en `api.post('/pwa/visits', ...)` y en `syncStore.queueVisit(visitData)` — mismo objeto.)

Y gatea el submit **solo si hay monto**: en `canSubmit` o al inicio de `submit()`:
```js
    if (hasPromisedAmount.value && isSimplifiedEnabled.value && requireConfirmation.value && !amountConfirmed.value) return
```
(Verifica `computed`/`ref` importados. Si `showPromise` se desactiva, no se exige confirmación.)

- [ ] **Step 4: Build + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2 && git add resources/js/pwa/components/collections/NoPaymentModal.vue && git commit -m 'feat(pwa): promesa de pago (no paga hoy) usa entrada simplificada'"
```

---

### Task 9: Frontend — quitar toggles por área en `CompanySettingsView` + helper text

**Files:**
- Modify: `resources/js/pwa/views/CompanySettingsView.vue`

- [ ] **Step 1: Eliminar los 2 bloques de toggle**

Borra el bloque template "En créditos" (222-239) y "En pagos" (241-258) completos.

- [ ] **Step 2: Quitar las vars del form**

En el `const form = ref({...})` (327-339) borra las líneas `simplified_input_credit: false,` y `simplified_input_payment: false,`. En `initFormFromStore()` (349-364) borra las 2 líneas `form.value.simplified_input_credit = ...` y `form.value.simplified_input_payment = ...`. (El `handleSave()` hace `{ ...form.value }` → al quitar las vars, ya no se envían al backend; el backend además ya las ignora tras Task 1.)

- [ ] **Step 3: Actualizar el helper text**

En la cabecera de la sección, reemplaza el texto `Captura montos sin ceros (ej: 1500 → $1.500.000)` (195) por:
```html
                        <p class="text-slate-600 text-xs">Captura montos sin ceros (ej: 1500 → $1.500.000). Aplica a créditos, pagos, gastos, aportes de socios y promesas de pago.</p>
```

- [ ] **Step 4: Build + verificar que no quedan refs + commit**
```bash
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2 && grep -n 'simplified_input_credit\|simplified_input_payment' resources/js/pwa/views/CompanySettingsView.vue || echo 'OK: sin refs a flags por area'"
wsl bash -lc "cd /var/www/html/credify && git add resources/js/pwa/views/CompanySettingsView.vue && git commit -m 'feat(pwa): un solo toggle maestro de entrada simplificada (fuera toggles por area)'"
```

---

### Task 10: Verificación holística + CHANGELOG

**Files:**
- Modify: `CHANGELOG.md`

- [ ] **Step 1: Suite + PHPStan + Pint + build**
```bash
wsl bash -lc "cd /var/www/html/credify && php artisan test --filter=SimplifiedInputExpandTest 2>&1 | tail -4"
wsl bash -lc "cd /var/www/html/credify && vendor/bin/phpstan analyse --level=5 app/ 2>&1 | tail -4"
wsl bash -lc "cd /var/www/html/credify && vendor/bin/pint --test 2>&1 | tail -3"
wsl bash -lc "cd /var/www/html/credify && npm run build 2>&1 | grep -iE 'error|built in' | tail -2"
```
Expected: tests verdes, PHPStan sin errores, Pint OK, build OK. (Si Pint reformatea, corre `vendor/bin/pint` y re-commit.)

- [ ] **Step 2: CHANGELOG**

Bajo `## [Sin publicar]` → `### Cambiado` (o `### Añadido`), añade: entrada simplificada ahora depende de **un solo toggle maestro** (se quitaron los toggles por área "En créditos"/"En pagos"; el gating backend es master-only) y **se aplica** también en Registrar Gasto, Transacción de Socio y el Monto Prometido de la visita "no paga hoy" (patrón: monto crudo + `is_simplified_amount`, el backend convierte). Ref al spec.

- [ ] **Step 3: Commit**
```bash
wsl bash -lc "cd /var/www/html/credify && git add CHANGELOG.md && git commit -m 'docs(pwa): CHANGELOG entrada simplificada — toggle unico + gastos/socios/promesa'"
```

---

## Deploy (post-merge, flujo — **full**: build + assets + backend)
Tras merge a `main` y realineo de `dev`: `npm run build` → scp `build`+`pwa-sw.js` a prod + swap atómico → `git pull` + `optimize` + reload php-fpm. Validación en dispositivo. Ver [[credify-prod-vm]].

---

## Self-Review (cobertura vs. spec)

- **Gating master-only (modelo + payload + update + simplifiedInput):** Task 1. ✅
- **Conversión en los 3 endpoints (gastos/socios/promesa), patrón crédito, gateado por maestro, con tests:** Tasks 2/3/4. ✅
- **Frontend: componente ampliado + 3 forms cableados + flags en payload (online y offline):** Tasks 5/6/7/8. ✅
- **Quitar los 2 toggles por área + helper text:** Task 9. ✅
- **Promesa opcional (no exigir/convertir sin monto):** Task 8 (`hasPromisedAmount`) + Task 4 (`filled('promised_amount')`). ✅
- **No doble multiplicación (crudo + backend convierte):** el componente ya emite crudo (sin cambio); los payloads envían el flag, no el valor convertido. ✅
- **No tocar multiplicador/confirmación/Filament/columna contexts:** ningún task lo hace (la columna queda vestigial). ✅
- **Verificación (tests + PHPStan + Pint + build + device):** Tasks + Task 10. ✅
- **Deploy full:** sección Deploy. ✅

**Placeholder scan:** los únicos valores "a verificar localmente" son enum/fact/nombres de tabla en los tests (categoría de `ExpenseCategory`, `Partner::factory()`/`capital_contributions`, `CollectionVisit::REASONS`/`VISIT_TYPES`, `Credit::factory()`) — son lookups verificables por el implementador, no placeholders de lógica; el resto es código exacto.

**Consistencia de tipos/nombres:** flags `is_simplified_amount`/`simplified_amount_confirmed` idénticos en backend (reglas + conversión) y frontend (payloads); getter `settingsStore.isSimplifiedInputEnabled` (maestro) usado en el componente y los 3 forms; `convertSimplifiedToReal()` + `isSimplifiedInputEnabled()` (firma conservada) coherentes entre modelo y los 4 call-sites. ✅
