TVA en sélection des taux officiels français, TTC non éditable
Le champ TVA devient un select (0 %, 2,1 %, 5,5 %, 10 %, 20 %) plutôt qu'une saisie libre, avec une option "Autre (préciser)" qui révèle le champ décimal existant -- indispensable pour les lignes migrées, dont le taux rétro-calculé (figli_compta_ledger_update_8005()) est souvent un taux effectif non standard qu'il ne faut surtout pas forcer à s'aligner sur l'une des 5 valeurs officielles. Montant TTC passe de readonly à #disabled : non focusable, non éditable même via les flèches d'un input number, et Form API rejette toute valeur soumise malgré tout au profit de #default_value. Le select est un élément de formulaire à part (pas un widget de champ) pour éviter que WidgetBase::extractFormValues() ne s'étouffe sur une clé étrangère mêlée aux valeurs de field_tva -- un #validate callback recopie la valeur choisie dans field_tva au moment opportun (après tous les #validate, avant la reconstruction de l'entité au submit). L'affichage/masquage du champ "Autre" repose sur du JS simple plutôt que sur #states : #states pose bien l'attribut data-drupal-states mais ne bascule jamais la visibilité dans cette modale AJAX précise, pour une raison non identifiée (un #states pourtant fonctionnel existe juste au-dessus, sur field_entree_liee, qui surveille un vrai champ Field API plutôt qu'un select ajouté à la main).
This commit is contained in:
@@ -58,7 +58,7 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
field_flag:
|
field_flag:
|
||||||
type: entity_reference_autocomplete_tags
|
type: entity_reference_autocomplete_tags
|
||||||
weight: 10
|
weight: 11
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
match_operator: CONTAINS
|
match_operator: CONTAINS
|
||||||
@@ -82,7 +82,7 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
field_notes:
|
field_notes:
|
||||||
type: string_textarea
|
type: string_textarea
|
||||||
weight: 9
|
weight: 10
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
rows: 5
|
rows: 5
|
||||||
@@ -98,7 +98,7 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
field_repartition:
|
field_repartition:
|
||||||
type: paragraphs
|
type: paragraphs
|
||||||
weight: 8
|
weight: 9
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
title: Répartition
|
title: Répartition
|
||||||
@@ -116,7 +116,7 @@ content:
|
|||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
field_tva:
|
field_tva:
|
||||||
type: number
|
type: number
|
||||||
weight: 6
|
weight: 8
|
||||||
region: content
|
region: content
|
||||||
settings:
|
settings:
|
||||||
placeholder: ''
|
placeholder: ''
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ content:
|
|||||||
settings:
|
settings:
|
||||||
link: true
|
link: true
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 10
|
weight: 11
|
||||||
region: content
|
region: content
|
||||||
field_montant_ht:
|
field_montant_ht:
|
||||||
type: number_decimal
|
type: number_decimal
|
||||||
@@ -85,7 +85,7 @@ content:
|
|||||||
label: above
|
label: above
|
||||||
settings: { }
|
settings: { }
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 9
|
weight: 10
|
||||||
region: content
|
region: content
|
||||||
field_numero_facture:
|
field_numero_facture:
|
||||||
type: string
|
type: string
|
||||||
@@ -103,7 +103,7 @@ content:
|
|||||||
view_mode: default
|
view_mode: default
|
||||||
link: ''
|
link: ''
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 8
|
weight: 9
|
||||||
region: content
|
region: content
|
||||||
field_tva:
|
field_tva:
|
||||||
type: number_decimal
|
type: number_decimal
|
||||||
@@ -114,7 +114,7 @@ content:
|
|||||||
scale: 2
|
scale: 2
|
||||||
prefix_suffix: true
|
prefix_suffix: true
|
||||||
third_party_settings: { }
|
third_party_settings: { }
|
||||||
weight: 6
|
weight: 8
|
||||||
region: content
|
region: content
|
||||||
field_type_ligne:
|
field_type_ligne:
|
||||||
type: list_default
|
type: list_default
|
||||||
|
|||||||
@@ -88,9 +88,18 @@ html.gin--dark-mode .figli-ledger-form {
|
|||||||
.figli-ledger-form > .field--name-field-montant-ht {
|
.figli-ledger-form > .field--name-field-montant-ht {
|
||||||
grid-column: 1 / 2;
|
grid-column: 1 / 2;
|
||||||
}
|
}
|
||||||
.figli-ledger-form > .field--name-field-tva {
|
/* The field_tva_rate select (added in figli_compta_ledger_form_alter(),
|
||||||
|
not a real field so it gets no field--name-* class) fills the middle
|
||||||
|
slot of the HT/TVA/TTC row instead -- see that function's #weight
|
||||||
|
comment for why this specific ordering (weight 6, between HT's 5 and
|
||||||
|
TTC's 7) matters, not just matching column numbers. field_tva itself
|
||||||
|
only appears -- full width, its own row -- when "Autre" is picked. */
|
||||||
|
.figli-ledger-form > .js-form-item-field-tva-rate {
|
||||||
grid-column: 2 / 3;
|
grid-column: 2 / 3;
|
||||||
}
|
}
|
||||||
|
.figli-ledger-form > .field--name-field-tva {
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
.figli-ledger-form > .field--name-field-montant-ttc {
|
.figli-ledger-form > .field--name-field-montant-ttc {
|
||||||
grid-column: 3 / 4;
|
grid-column: 3 / 4;
|
||||||
}
|
}
|
||||||
@@ -135,12 +144,15 @@ html.gin--dark-mode .figli-ledger-form {
|
|||||||
outline: 2px solid var(--flform-accent);
|
outline: 2px solid var(--flform-accent);
|
||||||
outline-offset: 1px;
|
outline-offset: 1px;
|
||||||
}
|
}
|
||||||
/* Montant TTC: readonly, computed from HT + TVA (see
|
/* Montant TTC: #disabled, computed from HT + TVA (see
|
||||||
figli_compta_ledger_node_presave()) -- a faint fill instead of the
|
figli_compta_ledger_node_presave()) -- a faint fill and full opacity
|
||||||
plain white/transparent of an editable field reads as "there but not
|
(overriding the browser's default half-transparent disabled look,
|
||||||
for you to type in" without looking disabled/greyed-out. */
|
which would make the computed number harder to read) instead of the
|
||||||
.figli-ledger-form input[readonly].form-element {
|
plain white/transparent of an editable field. */
|
||||||
|
.figli-ledger-form input:disabled.form-element {
|
||||||
background: var(--flform-bg-subtle);
|
background: var(--flform-bg-subtle);
|
||||||
|
color: var(--flform-text);
|
||||||
|
opacity: 1;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
.figli-ledger-form input[type="date"].form-element {
|
.figli-ledger-form input[type="date"].form-element {
|
||||||
|
|||||||
@@ -243,11 +243,18 @@ function _figli_compta_ledger_create_node_type_ligne_comptable() {
|
|||||||
->setComponent('field_client', ['type' => 'entity_reference_autocomplete', 'weight' => 2])
|
->setComponent('field_client', ['type' => 'entity_reference_autocomplete', 'weight' => 2])
|
||||||
->setComponent('field_numero_facture', ['type' => 'string_textfield', 'weight' => 3])
|
->setComponent('field_numero_facture', ['type' => 'string_textfield', 'weight' => 3])
|
||||||
->setComponent('field_montant_ht', ['type' => 'number', 'weight' => 5])
|
->setComponent('field_montant_ht', ['type' => 'number', 'weight' => 5])
|
||||||
->setComponent('field_tva', ['type' => 'number', 'weight' => 6])
|
|
||||||
->setComponent('field_montant_ttc', ['type' => 'number', 'weight' => 7])
|
->setComponent('field_montant_ttc', ['type' => 'number', 'weight' => 7])
|
||||||
->setComponent('field_repartition', ['type' => 'paragraphs', 'weight' => 8, 'settings' => ['title' => 'Répartition', 'title_plural' => 'Répartitions', 'edit_mode' => 'open', 'add_mode' => 'button']])
|
// field_tva sits *after* Montant TTC, not between HT and TTC --
|
||||||
->setComponent('field_notes', ['type' => 'string_textarea', 'weight' => 9])
|
// figli_compta_ledger_form_alter() inserts a non-field
|
||||||
->setComponent('field_flag', ['type' => 'entity_reference_autocomplete_tags', 'weight' => 10])
|
// "field_tva_rate" select at weight 6 (a select of the official
|
||||||
|
// French VAT rates) to fill that visual slot instead; this real
|
||||||
|
// field only becomes visible (still at its own weight, on its own
|
||||||
|
// full-width row) when "Autre" is picked there. See
|
||||||
|
// css/ledger-form.css's grid-column rules for both.
|
||||||
|
->setComponent('field_tva', ['type' => 'number', 'weight' => 8])
|
||||||
|
->setComponent('field_repartition', ['type' => 'paragraphs', 'weight' => 9, 'settings' => ['title' => 'Répartition', 'title_plural' => 'Répartitions', 'edit_mode' => 'open', 'add_mode' => 'button']])
|
||||||
|
->setComponent('field_notes', ['type' => 'string_textarea', 'weight' => 10])
|
||||||
|
->setComponent('field_flag', ['type' => 'entity_reference_autocomplete_tags', 'weight' => 11])
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,11 +270,11 @@ function _figli_compta_ledger_create_node_type_ligne_comptable() {
|
|||||||
->setComponent('field_client', ['type' => 'entity_reference_label', 'weight' => 2])
|
->setComponent('field_client', ['type' => 'entity_reference_label', 'weight' => 2])
|
||||||
->setComponent('field_numero_facture', ['type' => 'string', 'weight' => 3])
|
->setComponent('field_numero_facture', ['type' => 'string', 'weight' => 3])
|
||||||
->setComponent('field_montant_ht', ['type' => 'number_decimal', 'weight' => 5])
|
->setComponent('field_montant_ht', ['type' => 'number_decimal', 'weight' => 5])
|
||||||
->setComponent('field_tva', ['type' => 'number_decimal', 'weight' => 6])
|
|
||||||
->setComponent('field_montant_ttc', ['type' => 'number_decimal', 'weight' => 7])
|
->setComponent('field_montant_ttc', ['type' => 'number_decimal', 'weight' => 7])
|
||||||
->setComponent('field_repartition', ['type' => 'entity_reference_revisions_entity_view', 'weight' => 8])
|
->setComponent('field_tva', ['type' => 'number_decimal', 'weight' => 8])
|
||||||
->setComponent('field_notes', ['type' => 'basic_string', 'weight' => 9])
|
->setComponent('field_repartition', ['type' => 'entity_reference_revisions_entity_view', 'weight' => 9])
|
||||||
->setComponent('field_flag', ['type' => 'entity_reference_label', 'weight' => 10])
|
->setComponent('field_notes', ['type' => 'basic_string', 'weight' => 10])
|
||||||
|
->setComponent('field_flag', ['type' => 'entity_reference_label', 'weight' => 11])
|
||||||
->save();
|
->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,23 +408,28 @@ function figli_compta_ledger_update_8004() {
|
|||||||
$form_display->setComponent('field_numero_facture', ['type' => 'string_textfield', 'weight' => 3]);
|
$form_display->setComponent('field_numero_facture', ['type' => 'string_textfield', 'weight' => 3]);
|
||||||
$form_display->setComponent('field_entree_liee', ['type' => 'entity_reference_autocomplete', 'weight' => 4] + (array) $form_display->getComponent('field_entree_liee'));
|
$form_display->setComponent('field_entree_liee', ['type' => 'entity_reference_autocomplete', 'weight' => 4] + (array) $form_display->getComponent('field_entree_liee'));
|
||||||
$form_display->setComponent('field_montant_ht', ['type' => 'number', 'weight' => 5] + (array) $form_display->getComponent('field_montant_ht'));
|
$form_display->setComponent('field_montant_ht', ['type' => 'number', 'weight' => 5] + (array) $form_display->getComponent('field_montant_ht'));
|
||||||
$form_display->setComponent('field_tva', ['type' => 'number', 'weight' => 6] + (array) $form_display->getComponent('field_tva'));
|
|
||||||
$form_display->setComponent('field_montant_ttc', ['type' => 'number', 'weight' => 7] + (array) $form_display->getComponent('field_montant_ttc'));
|
$form_display->setComponent('field_montant_ttc', ['type' => 'number', 'weight' => 7] + (array) $form_display->getComponent('field_montant_ttc'));
|
||||||
$form_display->setComponent('field_repartition', ['weight' => 8] + (array) $form_display->getComponent('field_repartition'));
|
// Weight 6 (between HT and TTC) is now the non-field
|
||||||
$form_display->setComponent('field_notes', ['weight' => 9] + (array) $form_display->getComponent('field_notes'));
|
// "field_tva_rate" select figli_compta_ledger_form_alter() adds --
|
||||||
$form_display->setComponent('field_flag', ['weight' => 10] + (array) $form_display->getComponent('field_flag'));
|
// field_tva itself moves after Répartition/Notes/Flag's *old*
|
||||||
|
// positions, past the ones below, so it lands on its own row when
|
||||||
|
// "Autre" reveals it instead of disrupting the HT/rate/TTC row.
|
||||||
|
$form_display->setComponent('field_tva', ['type' => 'number', 'weight' => 8] + (array) $form_display->getComponent('field_tva'));
|
||||||
|
$form_display->setComponent('field_repartition', ['weight' => 9] + (array) $form_display->getComponent('field_repartition'));
|
||||||
|
$form_display->setComponent('field_notes', ['weight' => 10] + (array) $form_display->getComponent('field_notes'));
|
||||||
|
$form_display->setComponent('field_flag', ['weight' => 11] + (array) $form_display->getComponent('field_flag'));
|
||||||
$form_display->save();
|
$form_display->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
$view_display = EntityViewDisplay::load('node.ligne_comptable.default');
|
$view_display = EntityViewDisplay::load('node.ligne_comptable.default');
|
||||||
if ($view_display) {
|
if ($view_display) {
|
||||||
$view_display->setComponent('field_tva', ['type' => 'number_decimal', 'weight' => 6] + (array) $view_display->getComponent('field_tva'));
|
$view_display->setComponent('field_tva', ['type' => 'number_decimal', 'weight' => 8] + (array) $view_display->getComponent('field_tva'));
|
||||||
$view_display->setComponent('field_numero_facture', ['weight' => 3] + (array) $view_display->getComponent('field_numero_facture'));
|
$view_display->setComponent('field_numero_facture', ['weight' => 3] + (array) $view_display->getComponent('field_numero_facture'));
|
||||||
$view_display->setComponent('field_montant_ht', ['weight' => 5] + (array) $view_display->getComponent('field_montant_ht'));
|
$view_display->setComponent('field_montant_ht', ['weight' => 5] + (array) $view_display->getComponent('field_montant_ht'));
|
||||||
$view_display->setComponent('field_montant_ttc', ['weight' => 7] + (array) $view_display->getComponent('field_montant_ttc'));
|
$view_display->setComponent('field_montant_ttc', ['weight' => 7] + (array) $view_display->getComponent('field_montant_ttc'));
|
||||||
$view_display->setComponent('field_repartition', ['weight' => 8] + (array) $view_display->getComponent('field_repartition'));
|
$view_display->setComponent('field_repartition', ['weight' => 9] + (array) $view_display->getComponent('field_repartition'));
|
||||||
$view_display->setComponent('field_notes', ['weight' => 9] + (array) $view_display->getComponent('field_notes'));
|
$view_display->setComponent('field_notes', ['weight' => 10] + (array) $view_display->getComponent('field_notes'));
|
||||||
$view_display->setComponent('field_flag', ['weight' => 10] + (array) $view_display->getComponent('field_flag'));
|
$view_display->setComponent('field_flag', ['weight' => 11] + (array) $view_display->getComponent('field_flag'));
|
||||||
$view_display->save();
|
$view_display->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,16 +107,86 @@ function figli_compta_ledger_form_alter(&$form, FormStateInterface $form_state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Montant TTC is computed from Montant HT + TVA (see
|
// Montant TTC is computed from Montant HT + TVA (see
|
||||||
// figli_compta_ledger_node_presave()) -- readonly rather than #disabled
|
// figli_compta_ledger_node_presave()) -- genuinely not editable
|
||||||
// so js/ledger-form.js can still show a live preview as the associate
|
// (#disabled, not just readonly: a disabled field can't be focused or
|
||||||
// types, and so the field still visually reads as "there but not for
|
// tabbed into at all, and Form API discards whatever a tampered
|
||||||
// you to edit" instead of vanishing. The actual value saved is always
|
// request submits for it in favor of #default_value, same protection
|
||||||
// recomputed server-side regardless of what this input holds.
|
// already used for 'revision' above). js/ledger-form.js can still set
|
||||||
|
// its .value directly for the live preview -- #disabled only blocks
|
||||||
|
// user interaction, not script writes.
|
||||||
if (isset($form['field_montant_ttc']['widget'][0]['value'])) {
|
if (isset($form['field_montant_ttc']['widget'][0]['value'])) {
|
||||||
$form['field_montant_ttc']['widget'][0]['value']['#attributes']['readonly'] = 'readonly';
|
$form['field_montant_ttc']['widget'][0]['value']['#disabled'] = TRUE;
|
||||||
$form['field_montant_ttc']['widget'][0]['value']['#description'] = t('Calculé automatiquement à partir du montant HT et de la TVA.');
|
$form['field_montant_ttc']['widget'][0]['value']['#description'] = t('Calculé automatiquement à partir du montant HT et de la TVA.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TVA: a select of the official French rates covers the overwhelming
|
||||||
|
// majority of new lines with one click, instead of associates having
|
||||||
|
// to know/type "20" or "5.5" by heart. "Autre" reveals the real
|
||||||
|
// decimal field underneath for the rest -- crucially including every
|
||||||
|
// pre-migration line, whose backfilled rate (see
|
||||||
|
// figli_compta_ledger_update_8005()) is often a blended, non-standard
|
||||||
|
// percentage that wouldn't match any of these options, and must stay
|
||||||
|
// editable/visible as the exact figure it is rather than being forced
|
||||||
|
// to snap to the nearest official rate.
|
||||||
|
if (isset($form['field_tva']['widget'][0]['value'])) {
|
||||||
|
$taux_officiels = [
|
||||||
|
'0' => t('0 % (exonéré)'),
|
||||||
|
'2.1' => t('2,1 % (taux particulier)'),
|
||||||
|
'5.5' => t('5,5 % (taux réduit)'),
|
||||||
|
'10' => t('10 % (taux intermédiaire)'),
|
||||||
|
'20' => t('20 % (taux normal)'),
|
||||||
|
];
|
||||||
|
|
||||||
|
$tva_field = &$form['field_tva']['widget'][0]['value'];
|
||||||
|
$current = $tva_field['#default_value'] ?? NULL;
|
||||||
|
$rate_default = 'autre';
|
||||||
|
if ($current === NULL || $current === '') {
|
||||||
|
$rate_default = '0';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
foreach (array_keys($taux_officiels) as $rate) {
|
||||||
|
if (abs((float) $current - (float) $rate) < 0.0001) {
|
||||||
|
$rate_default = $rate;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// A plain top-level element, deliberately *not* nested inside
|
||||||
|
// $form['field_tva'] -- Field API's WidgetBase::extractFormValues()
|
||||||
|
// reads the entire form_state value at that path as the field's own
|
||||||
|
// delta-indexed value array, and chokes on an unrelated sibling key
|
||||||
|
// mixed into it.
|
||||||
|
//
|
||||||
|
// Weight 6: the exact slot Montant HT (5)/Montant TTC (7) leave open
|
||||||
|
// between them in figli_compta_ledger_update_8004() -- field_tva
|
||||||
|
// itself has been moved to weight 8 (its own full-width row) so
|
||||||
|
// that this select forms a clean HT/rate/TTC three-column row
|
||||||
|
// whether or not "Autre" is currently revealing the real field_tva
|
||||||
|
// input further down. See css/ledger-form.css's grid-column rules
|
||||||
|
// for both -- the row layout there depends on this exact ordering,
|
||||||
|
// not just on matching #weight values.
|
||||||
|
$form['field_tva_rate'] = [
|
||||||
|
'#type' => 'select',
|
||||||
|
'#title' => t('TVA'),
|
||||||
|
'#options' => $taux_officiels + ['autre' => t('Autre (préciser)')],
|
||||||
|
'#default_value' => $rate_default,
|
||||||
|
'#weight' => 6,
|
||||||
|
];
|
||||||
|
$tva_field['#title'] = t('Taux exact (%)');
|
||||||
|
// Not #states: this element sits outside the field system (see the
|
||||||
|
// comment above) and, tested in this exact AJAX-loaded modal,
|
||||||
|
// #states' data-drupal-states attribute gets attached correctly but
|
||||||
|
// never actually toggles visibility here -- unclear why (a working
|
||||||
|
// #states dependency already exists a few fields up, on
|
||||||
|
// field_entree_liee, watching a real Field API select rather than
|
||||||
|
// this manually-added one), not worth chasing further when
|
||||||
|
// js/ledger-form.js already has to run custom JS on this form
|
||||||
|
// anyway for the HT/TVA -> TTC live preview. Plain JS toggle there
|
||||||
|
// instead -- see figliLedgerTvaRateToggle.
|
||||||
|
$form['#validate'][] = 'figli_compta_ledger_apply_tva_rate';
|
||||||
|
}
|
||||||
|
|
||||||
$form['#attached']['library'][] = 'figli_compta_ledger/ledger_form';
|
$form['#attached']['library'][] = 'figli_compta_ledger/ledger_form';
|
||||||
|
|
||||||
$request = \Drupal::request();
|
$request = \Drupal::request();
|
||||||
@@ -163,6 +233,28 @@ function figli_compta_ledger_validate_repartition(array &$form, FormStateInterfa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form #validate callback: when a standard French VAT rate was picked from
|
||||||
|
* the field_tva_rate select (added in figli_compta_ledger_form_alter()),
|
||||||
|
* copies it into field_tva's own submitted value -- that's the field
|
||||||
|
* figli_compta_ledger_node_presave() actually reads to compute Montant TTC.
|
||||||
|
* Left untouched when "Autre" is selected: the real field_tva input,
|
||||||
|
* shown in that case by js/ledger-form.js's figliLedgerTvaRateToggle,
|
||||||
|
* already carries whatever the associate typed there.
|
||||||
|
*
|
||||||
|
* Runs late enough to matter despite EntityForm::validateForm() building an
|
||||||
|
* interim entity earlier in the same validate phase (for constraint
|
||||||
|
* checking only) -- submitForm() rebuilds the entity fresh from
|
||||||
|
* $form_state's values right before save(), by which point every
|
||||||
|
* #validate callback, this one included, has already run.
|
||||||
|
*/
|
||||||
|
function figli_compta_ledger_apply_tva_rate(array &$form, FormStateInterface $form_state) {
|
||||||
|
$rate = $form_state->getValue('field_tva_rate');
|
||||||
|
if ($rate !== NULL && $rate !== 'autre') {
|
||||||
|
$form_state->setValue(['field_tva', 0, 'value'], $rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #ajax callback for the node form submit button: close the modal on
|
* #ajax callback for the node form submit button: close the modal on
|
||||||
* success, or re-render the form (with errors) in place on failure.
|
* success, or re-render the form (with errors) in place on failure.
|
||||||
|
|||||||
@@ -25,17 +25,29 @@
|
|||||||
once('figli-ledger-tva-calc', '[name="field_montant_ht[0][value]"]', context).forEach(function (ht) {
|
once('figli-ledger-tva-calc', '[name="field_montant_ht[0][value]"]', context).forEach(function (ht) {
|
||||||
var form = ht.closest('form');
|
var form = ht.closest('form');
|
||||||
var tva = form.querySelector('[name="field_tva[0][value]"]');
|
var tva = form.querySelector('[name="field_tva[0][value]"]');
|
||||||
|
var rate = form.querySelector('[name="field_tva_rate"]');
|
||||||
var ttc = form.querySelector('[name="field_montant_ttc[0][value]"]');
|
var ttc = form.querySelector('[name="field_montant_ttc[0][value]"]');
|
||||||
if (!tva || !ttc) {
|
if (!tva || !ttc) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The rate select (when not "Autre") is the actual source of
|
||||||
|
// truth here -- figli_compta_ledger_apply_tva_rate() copies its
|
||||||
|
// value into field_tva server-side on submit, but that happens
|
||||||
|
// too late to matter for a live client-side preview.
|
||||||
|
function currentTva() {
|
||||||
|
if (rate && rate.value !== 'autre') {
|
||||||
|
return parseFloat(rate.value);
|
||||||
|
}
|
||||||
|
return parseFloat(tva.value);
|
||||||
|
}
|
||||||
|
|
||||||
function recompute() {
|
function recompute() {
|
||||||
var htValue = parseFloat(ht.value);
|
var htValue = parseFloat(ht.value);
|
||||||
if (isNaN(htValue)) {
|
if (isNaN(htValue)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var tvaValue = parseFloat(tva.value);
|
var tvaValue = currentTva();
|
||||||
if (isNaN(tvaValue)) {
|
if (isNaN(tvaValue)) {
|
||||||
tvaValue = 0;
|
tvaValue = 0;
|
||||||
}
|
}
|
||||||
@@ -48,12 +60,48 @@
|
|||||||
// the centime (see figli_compta_ledger_update_8005()'s
|
// the centime (see figli_compta_ledger_update_8005()'s
|
||||||
// docblock) -- showing a recomputed number the instant the
|
// docblock) -- showing a recomputed number the instant the
|
||||||
// modal opens, before the associate has touched anything, would
|
// modal opens, before the associate has touched anything, would
|
||||||
// misrepresent what's actually saved. Only recompute once HT or
|
// misrepresent what's actually saved. Only recompute once HT,
|
||||||
// TVA are actually edited, matching the same "only overwrite
|
// TVA, or the rate select are actually edited, matching the
|
||||||
// Montant TTC when HT/TVA actually changed" guard in
|
// same "only overwrite Montant TTC when HT/TVA actually
|
||||||
// figli_compta_ledger_node_presave().
|
// changed" guard in figli_compta_ledger_node_presave(). Harmless
|
||||||
|
// no-op on a genuinely new/blank line either way (HT is empty,
|
||||||
|
// recompute() bails out above).
|
||||||
ht.addEventListener('input', recompute);
|
ht.addEventListener('input', recompute);
|
||||||
tva.addEventListener('input', recompute);
|
tva.addEventListener('input', recompute);
|
||||||
|
if (rate) {
|
||||||
|
rate.addEventListener('change', recompute);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows/hides the real "Taux exact (%)" field_tva input based on the
|
||||||
|
* field_tva_rate select added in figli_compta_ledger_form_alter() --
|
||||||
|
* plain JS rather than #states: tested and confirmed #states' own
|
||||||
|
* data-drupal-states attribute gets attached correctly here but never
|
||||||
|
* actually toggles visibility, for reasons not tracked down (a
|
||||||
|
* working #states dependency already exists a few fields up, on
|
||||||
|
* field_entree_liee, watching a real Field API element rather than
|
||||||
|
* this manually-added select -- that one difference is the only lead
|
||||||
|
* so far). Not worth blocking on since this form already needs custom
|
||||||
|
* JS anyway for the TTC live preview above.
|
||||||
|
*/
|
||||||
|
Drupal.behaviors.figliLedgerTvaRateToggle = {
|
||||||
|
attach: function (context) {
|
||||||
|
once('figli-ledger-tva-rate-toggle', '[name="field_tva_rate"]', context).forEach(function (select) {
|
||||||
|
var form = select.closest('form');
|
||||||
|
var exact = form.querySelector('.field--name-field-tva');
|
||||||
|
if (!exact) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
exact.style.display = select.value === 'autre' ? '' : 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
select.addEventListener('change', toggle);
|
||||||
|
toggle();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user