Highlight versements not (fully) backed by their entrée
For "versement freelance" rows specifically: an amber outline plus a
badge when the versement either isn't linked to any entrée client at
all ("Non liée"), or is linked but reconciliationByEntree still shows
a residual on that entrée ("Reste à verser" / "Sur-versé", with the
amount in the tooltip). The residual belongs to the entrée as a whole,
not to any one sortie -- when several versements share an entrée, each
shows the same aggregate figure, since there's no way to attribute the
shortfall to one specific payment. No highlight when the linked entrée
isn't in the currently loaded window (can't tell either way -- same
accepted trade-off as reconciliationByEntree itself).
Verified: filtering to "Versement freelance" shows 21 of 25 loaded
rows flagged (17 unlinked, 4 with a reste-à-verser residual), the
remaining 4 fully-reconciled rows correctly unflagged, and the amber
outline resolves correctly in dark mode.
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
--figli-border: #dcdee2;
|
||||
--figli-error: #c9312b;
|
||||
--figli-positive: #1a7f37;
|
||||
--figli-warning: #d97a0a;
|
||||
--figli-col-hover: rgba(15, 23, 42, 0.05);
|
||||
|
||||
font-family: Inter, -apple-system, sans-serif;
|
||||
@@ -24,6 +25,7 @@ html.gin--dark-mode #figli-home-app {
|
||||
--figli-border: #3d3e42;
|
||||
--figli-error: #ff6b6b;
|
||||
--figli-positive: #4ade80;
|
||||
--figli-warning: #f0a94e;
|
||||
--figli-col-hover: rgba(255, 255, 255, 0.07);
|
||||
}
|
||||
|
||||
@@ -187,6 +189,24 @@ html.gin--dark-mode #figli-home-app {
|
||||
border-right: 1px solid var(--figli-error);
|
||||
}
|
||||
|
||||
/* Versement freelance not (fully) backed by its entrée: same thin-outline
|
||||
treatment as an error row, but amber -- it's not the ligne itself
|
||||
that's inconsistent (répartition still matches montant HT), it's the
|
||||
entrée/sortie relationship that isn't settled yet. Doesn't stack with
|
||||
figli-error-row's red in practice (different conditions), but scoped
|
||||
to :not() just in case a row is somehow both, so one outline wins
|
||||
rather than the borders visually competing. */
|
||||
#figli-home-app tr.figli-versement-warning-row:not(.figli-error-row) td {
|
||||
border-top: 1px solid var(--figli-warning);
|
||||
border-bottom: 1px solid var(--figli-warning);
|
||||
}
|
||||
#figli-home-app tr.figli-versement-warning-row:not(.figli-error-row) td:first-child {
|
||||
border-left: 1px solid var(--figli-warning);
|
||||
}
|
||||
#figli-home-app tr.figli-versement-warning-row:not(.figli-error-row) td:last-child {
|
||||
border-right: 1px solid var(--figli-warning);
|
||||
}
|
||||
|
||||
#figli-home-app td.figli-ecart {
|
||||
color: var(--figli-error);
|
||||
font-weight: 700;
|
||||
|
||||
@@ -383,6 +383,35 @@
|
||||
const detail = relevant.map((compte) => compte + ' : ' + this.formatEur(ecarts[compte])).join(', ');
|
||||
return { detail, comptes: relevant.length };
|
||||
},
|
||||
// Flags a "versement freelance" row that isn't (fully) backed by
|
||||
// the entrée client it pays out against: either not linked at all,
|
||||
// or linked but reconciliationByEntree still shows a residual on
|
||||
// that entrée. The residual belongs to the entrée as a whole, not
|
||||
// to any one sortie -- when several versements share an entrée,
|
||||
// each shows the same aggregate residual, since there's no way to
|
||||
// say which specific one is "the" shortfall. Null (no highlight)
|
||||
// when the linked entrée isn't in the currently loaded window --
|
||||
// same accepted trade-off as reconciliationByEntree itself.
|
||||
versementStatus(item) {
|
||||
if (item.type !== 'versement') return null;
|
||||
if (!item.entreeLieeId) {
|
||||
return { kind: 'non-liee', detail: 'Aucune entrée client liée.' };
|
||||
}
|
||||
const recon = this.reconciliationByEntree.get(item.entreeLieeId);
|
||||
if (!recon) return null;
|
||||
if (recon.resteAVerser > 0.01) {
|
||||
return { kind: 'reste', detail: 'Reste à verser sur l’entrée liée : ' + this.formatEur(recon.resteAVerser) };
|
||||
}
|
||||
if (recon.surVerse > 0.01) {
|
||||
return { kind: 'sur-verse', detail: 'Sur-versé sur l’entrée liée : ' + this.formatEur(recon.surVerse) };
|
||||
}
|
||||
return null;
|
||||
},
|
||||
versementStatusLabel(kind) {
|
||||
if (kind === 'non-liee') return 'Non liée';
|
||||
if (kind === 'reste') return 'Reste à verser';
|
||||
return 'Sur-versé';
|
||||
},
|
||||
// jj/mm/aa -- shorter than the API's ISO yyyy-mm-dd, saves column
|
||||
// width in a table already packed with 8 compte columns.
|
||||
formatDate(iso) {
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<tr v-if="item.isGroup" class="figli-group-row" :data-year="item.year">
|
||||
<td :colspan="6 + allComptes.length + 3">{{ item.label }} <span class="figli-note">({{ item.count }} lignes)</span></td>
|
||||
</tr>
|
||||
<tr v-else :class="{'figli-error-row': item.hasError}" :data-year="item.date ? item.date.slice(0, 4) : null">
|
||||
<tr v-else :class="{'figli-error-row': item.hasError, 'figli-versement-warning-row': versementStatus(item)}" :data-year="item.date ? item.date.slice(0, 4) : null">
|
||||
<td class="actions-col">
|
||||
<button
|
||||
v-if="item.linkable"
|
||||
@@ -158,6 +158,12 @@
|
||||
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="versementStatus(item)"
|
||||
class="figli-recon-badge"
|
||||
:class="{'is-anomalie': versementStatus(item).kind !== 'reste', 'is-reste': versementStatus(item).kind === 'reste'}"
|
||||
:title="versementStatus(item).detail"
|
||||
>⚠ {{ versementStatusLabel(versementStatus(item).kind) }}</span>
|
||||
</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