Track who paid each depense, with a "Commun" (shared) fallback
Adds a "payé par" field to transactions and recurring transactions: either a household member or null (shared/common expense). No per- member account balances — this is purely a "who paid" label, the household's overall balance is unchanged and unaffected by any filtering. - paid_by_user_id nullable FK on transactions and recurring_transactions - Suivi: "payé par" selector on both entry forms (desktop dropdown, mobile buttons), a filter above the transaction table, a "payé par" column, and a summary tile showing this month's depenses grouped by payer (including Commun) - Recurring transactions carry paid_by_user_id onto the transaction they generate when confirmed - Running balance is computed from all transactions regardless of the payer filter, so it never gets skewed by the active filter 11 new Pest tests (assignment, common fallback, non-member rejection, filter isolation from the balance calc, per-payer summary, recurring propagation). 69/69 total pass, Pint clean, verified end-to-end on production data (desktop + mobile, test row created and removed). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5ef655d16f
commit
9114bb2e8d
@@ -11,7 +11,7 @@
|
||||
@forelse ($recurrences as $recurring)
|
||||
<li class="px-4 py-3">
|
||||
@if ($editingId === $recurring->id)
|
||||
<form wire:submit="saveEdit" class="grid grid-cols-1 sm:grid-cols-4 gap-2 items-end">
|
||||
<form wire:submit="saveEdit" class="grid grid-cols-1 sm:grid-cols-5 gap-2 items-end">
|
||||
<div>
|
||||
<label for="editing-name-{{ $recurring->id }}" class="sr-only">Nom</label>
|
||||
<input wire:model="editingName" id="editing-name-{{ $recurring->id }}" type="text" class="w-full bg-surface border-border-strong text-text rounded-md text-sm py-1" autofocus />
|
||||
@@ -24,6 +24,15 @@
|
||||
<label for="editing-day-{{ $recurring->id }}" class="sr-only">Jour du mois</label>
|
||||
<input wire:model="editingDayOfMonth" id="editing-day-{{ $recurring->id }}" type="number" min="1" max="28" class="w-full bg-surface border-border-strong text-text rounded-md text-sm py-1" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="editing-paid-by-{{ $recurring->id }}" class="sr-only">Payé par</label>
|
||||
<select wire:model="editingPaidByUserId" id="editing-paid-by-{{ $recurring->id }}" class="w-full rounded-md bg-surface border-border-strong text-text text-sm py-1 focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">
|
||||
<option value="">Commun</option>
|
||||
@foreach ($members as $member)
|
||||
<option value="{{ $member->id }}">{{ $member->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<button type="submit" class="text-xs text-positive hover:underline rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">Sauver</button>
|
||||
<button type="button" wire:click="cancelEdit" class="text-xs text-text-muted hover:underline rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">Annuler</button>
|
||||
@@ -37,7 +46,7 @@
|
||||
<span class="text-text-muted">— {{ $recurring->category->name }}</span>
|
||||
</p>
|
||||
<p class="text-xs text-text-muted">
|
||||
{{ number_format($recurring->amount, 2, ',', ' ') }} € · le {{ $recurring->day_of_month }} de chaque mois
|
||||
{{ number_format($recurring->amount, 2, ',', ' ') }} € · le {{ $recurring->day_of_month }} de chaque mois · {{ $recurring->paidBy?->name ?? 'Commun' }}
|
||||
@unless ($recurring->active) · <span class="text-danger">en pause</span> @endunless
|
||||
</p>
|
||||
</div>
|
||||
@@ -56,7 +65,7 @@
|
||||
@endforelse
|
||||
</ul>
|
||||
|
||||
<form wire:submit="add" class="px-4 py-4 bg-surface-alt grid grid-cols-1 sm:grid-cols-5 gap-3 items-end">
|
||||
<form wire:submit="add" class="px-4 py-4 bg-surface-alt grid grid-cols-1 sm:grid-cols-6 gap-3 items-end">
|
||||
<div>
|
||||
<x-input-label for="name" value="Nom" />
|
||||
<x-text-input wire:model="name" id="name" type="text" class="block mt-1 w-full text-sm" placeholder="Loyer" />
|
||||
@@ -82,6 +91,15 @@
|
||||
<x-text-input wire:model="dayOfMonth" id="dayOfMonth" type="number" min="1" max="28" class="block mt-1 w-full text-sm" />
|
||||
<x-input-error :messages="$errors->get('dayOfMonth')" class="mt-1" />
|
||||
</div>
|
||||
<div>
|
||||
<x-input-label for="paidByUserId" value="Payé par" />
|
||||
<select wire:model="paidByUserId" id="paidByUserId" class="block mt-1 w-full rounded-md bg-surface border-border-strong text-text text-sm focus:outline-none focus-visible:ring-2 focus-visible:ring-focus-ring">
|
||||
<option value="">Commun</option>
|
||||
@foreach ($members as $member)
|
||||
<option value="{{ $member->id }}">{{ $member->name }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<x-primary-button class="w-full justify-center">Ajouter</x-primary-button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user