Make Client/Facture/Libellé editable in place, same as the type badge
New POST /lignes/{node}/champ endpoint (LedgerActionsController::updateField(),
whitelisted to client/facture/libelle -> field_client/field_numero_facture/
field_notes) mirrors updateType(): skips the répartition invariant check
for this save (client/facture/libellé never touch montant_ht or
field_repartition, so it can only ever leave a pre-existing historical
mismatch as it was, never introduce one), wrapped in the same
skip_validation state flag with a try/finally.
Client resolves the typed text against existing "Client" taxonomy terms
only (same known-names list the toolbar's Client filter already offers
via a datalist) -- a non-match is rejected with a clear error rather
than silently creating a new term from a typo.
Frontend mirrors the existing editingTypeId/startEditType/saveType
pattern exactly, generalized to any of the three fields via a single
{id, field} editingCell state.
Verified live: editing all three fields on a row with a known
répartition écart succeeds (bypass confirmed), an unknown client name
is rejected with a visible error and the display value stays unchanged,
and the database was confirmed clean of test artifacts afterward.
This commit is contained in:
@@ -144,7 +144,19 @@
|
||||
</button>
|
||||
</td>
|
||||
<td>{{ formatDate(item.date) }}</td>
|
||||
<td>{{ item.client || '—' }}</td>
|
||||
<td>
|
||||
<input
|
||||
v-if="isEditingCell(item, 'client')"
|
||||
type="text"
|
||||
class="figli-inline-input"
|
||||
list="figli-client-datalist"
|
||||
:value="item.client"
|
||||
@change="saveCell(item, 'client', $event)"
|
||||
@blur="editingCell = null"
|
||||
@keyup.enter="$event.target.blur()"
|
||||
/>
|
||||
<span v-else class="figli-editable-cell" title="Cliquer pour modifier" @click="startEditCell(item, 'client')">{{ item.client || '—' }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<select
|
||||
v-if="editingTypeId === item.id"
|
||||
@@ -163,28 +175,50 @@
|
||||
@click="startEditType(item)"
|
||||
>{{ typeLabel(item.type) }}</span>
|
||||
</td>
|
||||
<td>{{ item.facture }}</td>
|
||||
<td>
|
||||
<input
|
||||
v-if="isEditingCell(item, 'facture')"
|
||||
type="text"
|
||||
class="figli-inline-input"
|
||||
:value="item.facture"
|
||||
@change="saveCell(item, 'facture', $event)"
|
||||
@blur="editingCell = null"
|
||||
@keyup.enter="$event.target.blur()"
|
||||
/>
|
||||
<span v-else class="figli-editable-cell" title="Cliquer pour modifier" @click="startEditCell(item, 'facture')">{{ item.facture }}</span>
|
||||
</td>
|
||||
<td class="figli-libelle">
|
||||
{{ item.libelle }}
|
||||
<span
|
||||
v-if="item.type === 'entree' && reconciliationByEntree.get(item.id) && reconciliationByEntree.get(item.id).count > 0"
|
||||
class="figli-recon-badge is-clickable"
|
||||
:class="{'is-anomalie': reconciliationByEntree.get(item.id).surVerse > 0, 'is-reste': reconciliationByEntree.get(item.id).resteAVerser > 0}"
|
||||
:title="reconciliationByEntree.get(item.id).detail"
|
||||
@click="toggleEntreeFilter(item.id)"
|
||||
>{{ reconciliationByEntree.get(item.id).count }} sortie{{ reconciliationByEntree.get(item.id).count > 1 ? 's' : '' }} liée{{ reconciliationByEntree.get(item.id).count > 1 ? 's' : '' }}<template v-if="reconciliationByEntree.get(item.id).resteAVerser > 0"> · reste {{ formatEur(reconciliationByEntree.get(item.id).resteAVerser) }}</template><template v-if="reconciliationByEntree.get(item.id).surVerse > 0"> · sur-versé {{ formatEur(reconciliationByEntree.get(item.id).surVerse) }}</template></span>
|
||||
<span
|
||||
v-if="item.type === 'ouverture' && ouvertureEcart(item)"
|
||||
class="figli-recon-badge is-anomalie"
|
||||
:title="'Écart avec la clôture calculée de ' + (item.date.slice(0, 4) - 1) + ' : ' + ouvertureEcart(item).detail"
|
||||
>⚠ écart clôture {{ item.date.slice(0, 4) - 1 }} ({{ ouvertureEcart(item).comptes }} compte{{ ouvertureEcart(item).comptes > 1 ? 's' : '' }})</span>
|
||||
<span
|
||||
v-if="linkStatus(item)"
|
||||
class="figli-recon-badge is-clickable"
|
||||
:class="linkStatusClasses(linkStatus(item).kind)"
|
||||
:title="item.entreeLieeIds.length ? linkStatus(item).detail + ' -- cliquer pour voir la ou les entrées liées' : linkStatus(item).detail + ' -- cliquer pour lier une entrée client'"
|
||||
@click="item.entreeLieeIds.length ? toggleEntreeFilter(item.entreeLieeIds[0]) : openLinkForm(item.nid)"
|
||||
>{{ linkStatus(item).kind === 'ok' ? '' : '⚠ ' }}{{ linkStatusLabel(linkStatus(item).kind) }}</span>
|
||||
<input
|
||||
v-if="isEditingCell(item, 'libelle')"
|
||||
type="text"
|
||||
class="figli-inline-input"
|
||||
:value="item.libelle"
|
||||
@change="saveCell(item, 'libelle', $event)"
|
||||
@blur="editingCell = null"
|
||||
@keyup.enter="$event.target.blur()"
|
||||
/>
|
||||
<template v-else>
|
||||
<span class="figli-editable-cell" title="Cliquer pour modifier" @click="startEditCell(item, 'libelle')">{{ item.libelle }}</span>
|
||||
<span
|
||||
v-if="item.type === 'entree' && reconciliationByEntree.get(item.id) && reconciliationByEntree.get(item.id).count > 0"
|
||||
class="figli-recon-badge is-clickable"
|
||||
:class="{'is-anomalie': reconciliationByEntree.get(item.id).surVerse > 0, 'is-reste': reconciliationByEntree.get(item.id).resteAVerser > 0}"
|
||||
:title="reconciliationByEntree.get(item.id).detail"
|
||||
@click="toggleEntreeFilter(item.id)"
|
||||
>{{ reconciliationByEntree.get(item.id).count }} sortie{{ reconciliationByEntree.get(item.id).count > 1 ? 's' : '' }} liée{{ reconciliationByEntree.get(item.id).count > 1 ? 's' : '' }}<template v-if="reconciliationByEntree.get(item.id).resteAVerser > 0"> · reste {{ formatEur(reconciliationByEntree.get(item.id).resteAVerser) }}</template><template v-if="reconciliationByEntree.get(item.id).surVerse > 0"> · sur-versé {{ formatEur(reconciliationByEntree.get(item.id).surVerse) }}</template></span>
|
||||
<span
|
||||
v-if="item.type === 'ouverture' && ouvertureEcart(item)"
|
||||
class="figli-recon-badge is-anomalie"
|
||||
:title="'Écart avec la clôture calculée de ' + (item.date.slice(0, 4) - 1) + ' : ' + ouvertureEcart(item).detail"
|
||||
>⚠ écart clôture {{ item.date.slice(0, 4) - 1 }} ({{ ouvertureEcart(item).comptes }} compte{{ ouvertureEcart(item).comptes > 1 ? 's' : '' }})</span>
|
||||
<span
|
||||
v-if="linkStatus(item)"
|
||||
class="figli-recon-badge is-clickable"
|
||||
:class="linkStatusClasses(linkStatus(item).kind)"
|
||||
:title="item.entreeLieeIds.length ? linkStatus(item).detail + ' -- cliquer pour voir la ou les entrées liées' : linkStatus(item).detail + ' -- cliquer pour lier une entrée client'"
|
||||
@click="item.entreeLieeIds.length ? toggleEntreeFilter(item.entreeLieeIds[0]) : openLinkForm(item.nid)"
|
||||
>{{ linkStatus(item).kind === 'ok' ? '' : '⚠ ' }}{{ linkStatusLabel(linkStatus(item).kind) }}</span>
|
||||
</template>
|
||||
</td>
|
||||
<td class="amount" :class="montantClass(item.montant_ht)">{{ formatEur(item.montant_ht) }}</td>
|
||||
<td class="amount">{{ formatEur(item.montant_ttc) }}</td>
|
||||
|
||||
Reference in New Issue
Block a user