Link sorties to the entrée client they pay out against

New field_entree_liee (entity reference, node -> node) on
ligne_comptable, restricted to entrée-type nodes via a custom
EntreeClientSelection plugin -- narrows further to the same client as
the sortie being linked when one is already known, using the
referencing-entity context Drupal's selection handler API passes
through (getSelectionHandler($field, $entity)).

Quick-link UI (per the associates' explicit ask: no need to open the
full ligne_comptable form just for this):
- A chain-link icon next to the edit pencil on versement/achat/
  hébergement rows (the only types that pay out against a client
  invoice) opens LinkEntreeForm, a one-field AJAX modal, reusing the
  same modal/close-on-save plumbing as the edit form. Filled/colored
  when already linked, with the linked entrée's label on hover.
  Also present (states-hidden unless one of those three types is
  selected) on the full node form for whoever's already there anyway.
- Entrée rows get a reconciliation badge once at least one sortie
  links back to them, clickable to drill the table down to just that
  entrée and its linked sorties.

Conformity check assumes multi-compte répartition on both sides (an
entrée's répartition and each linked sortie's répartition can each
split across several comptes -- confirmed this is the real shape of
"hébergement" sorties, e.g. OVH/HETZNER renewals split across all 8
comptes, even though versement/achat lines happen to always be
single-compte in the current data). Per compte, compares the entrée's
répartition share (positive, owed) against the summed répartition of
every linked sortie (negative, paid) -- a residual near zero means
settled, positive means still owed ("reste à verser"), negative means
overpaid ("sur-versé", flagged for a closer look).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 12:22:47 +02:00
co-authored by Claude Sonnet 5
parent 27a799e937
commit d04d0e8824
12 changed files with 358 additions and 4 deletions
@@ -5,6 +5,7 @@ dependencies:
config:
- field.field.node.ligne_comptable.field_client
- field.field.node.ligne_comptable.field_date_ligne
- field.field.node.ligne_comptable.field_entree_liee
- field.field.node.ligne_comptable.field_montant_ht
- field.field.node.ligne_comptable.field_montant_ttc
- field.field.node.ligne_comptable.field_notes
@@ -42,6 +43,16 @@ content:
region: content
settings: { }
third_party_settings: { }
field_entree_liee:
type: entity_reference_autocomplete
weight: 2
region: content
settings:
match_operator: CONTAINS
match_limit: 10
size: 60
placeholder: ''
third_party_settings: { }
field_montant_ht:
type: number
weight: 3
@@ -5,6 +5,7 @@ dependencies:
config:
- field.field.node.ligne_comptable.field_client
- field.field.node.ligne_comptable.field_date_ligne
- field.field.node.ligne_comptable.field_entree_liee
- field.field.node.ligne_comptable.field_montant_ht
- field.field.node.ligne_comptable.field_montant_ttc
- field.field.node.ligne_comptable.field_notes
@@ -38,6 +39,14 @@ content:
third_party_settings: { }
weight: 0
region: content
field_entree_liee:
type: entity_reference_label
label: above
settings:
link: true
third_party_settings: { }
weight: 2
region: content
field_montant_ht:
type: number_decimal
label: above
@@ -0,0 +1,23 @@
uuid: c2d68287-8e24-4529-a035-39395acca4d3
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_entree_liee
- node.type.ligne_comptable
id: node.ligne_comptable.field_entree_liee
field_name: field_entree_liee
entity_type: node
bundle: ligne_comptable
label: 'Entrée client liée'
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
handler: 'figli_compta_ledger:entree_client'
handler_settings:
target_bundles:
ligne_comptable: ligne_comptable
field_type: entity_reference
@@ -0,0 +1,19 @@
uuid: d7148451-7a96-4515-b0b5-42ad9fecbdce
langcode: en
status: true
dependencies:
module:
- node
id: node.field_entree_liee
field_name: field_entree_liee
entity_type: node
type: entity_reference
settings:
target_type: node
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false