démockage pour type quantité restante

This commit is contained in:
Daniel Allaire 2026-03-16 22:40:29 -04:00
parent 8f36fa8fd3
commit 3397a00d42
10 changed files with 462 additions and 54 deletions

View file

@ -108,6 +108,33 @@ def main() -> int:
exit_with(2, f"CRITICAL - {args.label}: seuils incohérents")
elif args.probe_type == "remaining_quantity":
if args.source_type != "manual_value":
exit_with(2, f"CRITICAL - source_type non supporté: {args.source_type}")
if args.unit not in {"%", "units", "litres"}:
exit_with(2, f"CRITICAL - unité non supportée: {args.unit}")
if args.inputs_file and args.item_key:
item = load_input_item(args.inputs_file, args.item_key)
metric = float(str(item.get("value", "")).strip())
elif args.source_value:
metric = float(str(args.source_value).strip())
else:
raise ValueError("manual_value exige inputs-file/item-key ou source-value")
unit_suffix = args.unit
if args.critical_lt is not None and metric < args.critical_lt:
exit_with(2, f"CRITICAL - {args.label}: {metric:.1f} {unit_suffix} restants")
if args.warning_lt is not None and metric < args.warning_lt:
exit_with(1, f"WARNING - {args.label}: {metric:.1f} {unit_suffix} restants")
if args.ok_gte is not None and metric >= args.ok_gte:
exit_with(0, f"OK - {args.label}: {metric:.1f} {unit_suffix} restants")
if args.unknown_gte is not None and metric >= args.unknown_gte:
exit_with(3, f"UNKNOWN - {args.label}: {metric:.1f} {unit_suffix} restants")
exit_with(2, f"CRITICAL - {args.label}: seuils incohérents")
else:
exit_with(2, f"CRITICAL - probe_type non supporté: {args.probe_type}")

View file

@ -1200,6 +1200,24 @@ domains:
- name: verification-carburant-generatrice
date: 2026-04-01
notes: Vérification de l'approvisionnement propane lié à la génératrice
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/resilience.yaml
item_key: verification-carburant-generatrice
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: verification-procedure-bascule
date: 2026-04-15
notes: Réviser la procédure de bascule en mode secours
@ -1225,6 +1243,24 @@ domains:
- name: verification-stock-lampes-piles
date: 2026-05-01
notes: Vérification des lampes, piles et éclairage d'urgence
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/resilience.yaml
item_key: verification-stock-lampes-piles
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: verification-trousses-urgence
date: 2026-05-15
notes: Vérification des trousses d'urgence
@ -1301,21 +1337,129 @@ domains:
- name: verification-reserve-eau
date: 2026-04-15
notes: Vérification de la réserve d'eau potable
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: verification-reserve-eau
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: verification-mylar-absorbeurs
date: 2026-05-01
notes: Vérifier l'intégrité des emballages Mylar et absorbeurs
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: verification-mylar-absorbeurs
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revue-inventaire-conserves
date: 2026-04-15
notes: Revue des conserves et dates de rotation
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: revue-inventaire-conserves
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revue-inventaire-farine-riz-pates
date: 2026-04-01
notes: Vérification des gros stocks alimentaires de base
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: revue-inventaire-farine-riz-pates
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: verification-bacs-legumes-racines
date: 2026-10-01
notes: Vérification des bacs de stockage de légumes racines
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: verification-bacs-legumes-racines
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revue-supplements-vitamines
date: 2026-05-01
notes: Vérification du stock de suppléments et dates utiles
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/stock-alimentaire.yaml
item_key: revue-supplements-vitamines
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
sante:
- name: verification-trousse-premiers-soins
date: 2026-04-01
@ -1766,9 +1910,45 @@ domains:
- name: revision-pharmacopée-jardin
date: 2026-05-01
notes: Vérification du stock de soins pour végétaux
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/jardin.yaml
item_key: revision-pharmacopée-jardin
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revision-armoire-produits-jardin
date: 2026-05-01
notes: Vérification et ordre de l'armoire des produits pour végétaux
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/jardin.yaml
item_key: revision-armoire-produits-jardin
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
outils-et-equipements:
- name: entretien-outils-jardin
date: 2026-04-15
@ -2924,6 +3104,24 @@ domains:
- name: verification-reserve-pieces
date: 2026-06-01
notes: Vérifier les pièces de rechange critiques
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/actifs-chezlepro.yaml
item_key: verification-reserve-pieces
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revision-actifs-transferts
date: 2026-06-15
notes: Réviser les actifs transférés ou à transférer à l'entreprise
@ -3283,9 +3481,45 @@ domains:
- name: verification-stock-nourriture-chats
date: 2026-04-15
notes: Vérification du stock de nourriture pour chats
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/animaux.yaml
item_key: verification-stock-nourriture-chats
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: verification-friandises-et-litiere
date: 2026-04-15
notes: Vérification des stocks de friandises et de litière
probe:
type: remaining_quantity
source:
type: manual_value
inputs_file: /opt/life-noc/data/inputs/animaux.yaml
item_key: verification-friandises-et-litiere
metric:
unit: "%"
thresholds:
ok_gte: 50
warning_lt: 50
critical_lt: 25
policy:
on_error: critical
ui:
form_mode: remaining_quantity
allow_complete: false
allow_manual_edit: true
- name: revision-routine-soins-animaux
date: 2026-05-01
notes: Revue de la routine de soins et des besoins matériels des chats

View file

@ -56,11 +56,19 @@ apply Service "actifs-chezlepro-verification-serveurs-et-composants" {
}
apply Service "actifs-chezlepro-verification-reserve-pieces" {
import "service_echeance"
vars.date_echeance = "2026-06-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/actifs-chezlepro.yaml"
vars.life_noc_item_key = "verification-reserve-pieces"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-reserve-pieces"
groups = [ "ACTIFS-CHEZLEPRO" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérifier les pièces de rechange critiques"
vars.instructions_url = "/life-noc/item/actifs-chezlepro/verification-reserve-pieces"
assign where host.name == "life-noc"

View file

@ -5,22 +5,38 @@
*/
apply Service "animaux-verification-stock-nourriture-chats" {
import "service_echeance"
vars.date_echeance = "2026-04-15"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/animaux.yaml"
vars.life_noc_item_key = "verification-stock-nourriture-chats"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-stock-nourriture-chats"
groups = [ "ANIMAUX" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification du stock de nourriture pour chats"
vars.instructions_url = "/life-noc/item/animaux/verification-stock-nourriture-chats"
assign where host.name == "life-noc"
}
apply Service "animaux-verification-friandises-et-litiere" {
import "service_echeance"
vars.date_echeance = "2026-04-15"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/animaux.yaml"
vars.life_noc_item_key = "verification-friandises-et-litiere"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-friandises-et-litiere"
groups = [ "ANIMAUX" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification des stocks de friandises et de litière"
vars.instructions_url = "/life-noc/item/animaux/verification-friandises-et-litiere"
assign where host.name == "life-noc"

View file

@ -165,22 +165,38 @@ apply Service "jardin-entretien-houblon" {
}
apply Service "jardin-revision-pharmacopée-jardin" {
import "service_echeance"
vars.date_echeance = "2026-05-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/jardin.yaml"
vars.life_noc_item_key = "revision-pharmacopée-jardin"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "revision-pharmacopée-jardin"
groups = [ "JARDIN" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification du stock de soins pour végétaux"
vars.instructions_url = "/life-noc/item/jardin/revision-pharmacopée-jardin"
assign where host.name == "life-noc"
}
apply Service "jardin-revision-armoire-produits-jardin" {
import "service_echeance"
vars.date_echeance = "2026-05-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/jardin.yaml"
vars.life_noc_item_key = "revision-armoire-produits-jardin"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "revision-armoire-produits-jardin"
groups = [ "JARDIN" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification et ordre de l'armoire des produits pour végétaux"
vars.instructions_url = "/life-noc/item/jardin/revision-armoire-produits-jardin"
assign where host.name == "life-noc"

View file

@ -25,11 +25,19 @@ apply Service "resilience-test-generatrice-propane" {
}
apply Service "resilience-verification-carburant-generatrice" {
import "service_echeance"
vars.date_echeance = "2026-04-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/resilience.yaml"
vars.life_noc_item_key = "verification-carburant-generatrice"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-carburant-generatrice"
groups = [ "RESILIENCE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification de l'approvisionnement propane lié à la génératrice"
vars.instructions_url = "/life-noc/item/resilience/verification-carburant-generatrice"
assign where host.name == "life-noc"
@ -56,11 +64,19 @@ apply Service "resilience-verification-procedure-bascule" {
}
apply Service "resilience-verification-stock-lampes-piles" {
import "service_echeance"
vars.date_echeance = "2026-05-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/resilience.yaml"
vars.life_noc_item_key = "verification-stock-lampes-piles"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-stock-lampes-piles"
groups = [ "RESILIENCE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification des lampes, piles et éclairage d'urgence"
vars.instructions_url = "/life-noc/item/resilience/verification-stock-lampes-piles"
assign where host.name == "life-noc"

View file

@ -25,66 +25,114 @@ apply Service "stock-alimentaire-rotation-nourriture-seche" {
}
apply Service "stock-alimentaire-verification-reserve-eau" {
import "service_echeance"
vars.date_echeance = "2026-04-15"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "verification-reserve-eau"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-reserve-eau"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification de la réserve d'eau potable"
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-reserve-eau"
assign where host.name == "life-noc"
}
apply Service "stock-alimentaire-verification-mylar-absorbeurs" {
import "service_echeance"
vars.date_echeance = "2026-05-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "verification-mylar-absorbeurs"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-mylar-absorbeurs"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérifier l'intégrité des emballages Mylar et absorbeurs"
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-mylar-absorbeurs"
assign where host.name == "life-noc"
}
apply Service "stock-alimentaire-revue-inventaire-conserves" {
import "service_echeance"
vars.date_echeance = "2026-04-15"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "revue-inventaire-conserves"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "revue-inventaire-conserves"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Revue des conserves et dates de rotation"
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-inventaire-conserves"
assign where host.name == "life-noc"
}
apply Service "stock-alimentaire-revue-inventaire-farine-riz-pates" {
import "service_echeance"
vars.date_echeance = "2026-04-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "revue-inventaire-farine-riz-pates"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "revue-inventaire-farine-riz-pates"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification des gros stocks alimentaires de base"
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-inventaire-farine-riz-pates"
assign where host.name == "life-noc"
}
apply Service "stock-alimentaire-verification-bacs-legumes-racines" {
import "service_echeance"
vars.date_echeance = "2026-10-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "verification-bacs-legumes-racines"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "verification-bacs-legumes-racines"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification des bacs de stockage de légumes racines"
vars.instructions_url = "/life-noc/item/stock-alimentaire/verification-bacs-legumes-racines"
assign where host.name == "life-noc"
}
apply Service "stock-alimentaire-revue-supplements-vitamines" {
import "service_echeance"
vars.date_echeance = "2026-05-01"
vars.mock_state = "OK"
vars.mock_message = "Sous contrôle"
import "service_life_noc_probe"
vars.life_noc_probe_type = "remaining_quantity"
vars.life_noc_source_type = "manual_value"
vars.life_noc_source_value = ""
vars.life_noc_inputs_file = "/opt/life-noc/data/inputs/stock-alimentaire.yaml"
vars.life_noc_item_key = "revue-supplements-vitamines"
vars.life_noc_metric_unit = "%"
vars.life_noc_label = "revue-supplements-vitamines"
groups = [ "STOCK-ALIMENTAIRE" ]
vars.life_noc_threshold_ok_gte = "50"
vars.life_noc_threshold_warning_lt = "50"
vars.life_noc_threshold_critical_lt = "25"
vars.life_noc_on_error = "critical"
notes = "Vérification du stock de suppléments et dates utiles"
vars.instructions_url = "/life-noc/item/stock-alimentaire/revue-supplements-vitamines"
assign where host.name == "life-noc"

View file

@ -176,4 +176,22 @@ def compute_state_for_item(domain: str, item_key: str) -> str:
return "OK"
return "CRITICAL"
if probe_type == "remaining_quantity":
if source_type != "manual_value":
return "CRITICAL"
if metric_unit not in {"%", "units", "litres"}:
return "CRITICAL"
value = float(str(item.get("value", "")).strip())
if "critical_lt" in thresholds and value < float(thresholds["critical_lt"]):
return "CRITICAL"
if "warning_lt" in thresholds and value < float(thresholds["warning_lt"]):
return "WARNING"
if "ok_gte" in thresholds and value >= float(thresholds["ok_gte"]):
return "OK"
if "unknown_gte" in thresholds and value >= float(thresholds["unknown_gte"]):
return "UNKNOWN"
return "CRITICAL"
return "CRITICAL"

View file

@ -202,8 +202,8 @@ def validate_probe(item: dict) -> None:
raise ValueError("probe doit être un objet")
probe_type = str(probe.get("type", "")).strip()
if probe_type not in {"elapsed_time", "days_until_due", "elapsed_distance"}:
raise ValueError("seuls probe.type=elapsed_time, days_until_due et elapsed_distance sont supportés")
if probe_type not in {"elapsed_time", "days_until_due", "elapsed_distance", "remaining_quantity"}:
raise ValueError("seuls probe.type=elapsed_time, days_until_due, elapsed_distance et remaining_quantity sont supportés")
source = probe.get("source")
if not isinstance(source, dict):
@ -223,6 +223,11 @@ def validate_probe(item: dict) -> None:
raise ValueError("seul probe.source.type=manual_counter est supporté pour elapsed_distance")
if not has_store_ref:
raise ValueError("probe.source.inputs_file + item_key requis pour elapsed_distance")
elif probe_type == "remaining_quantity":
if source_type != "manual_value":
raise ValueError("seul probe.source.type=manual_value est supporté pour remaining_quantity")
if not has_store_ref:
raise ValueError("probe.source.inputs_file + item_key requis pour remaining_quantity")
metric = probe.get("metric")
if not isinstance(metric, dict):
@ -232,6 +237,8 @@ def validate_probe(item: dict) -> None:
raise ValueError("seul probe.metric.unit=days est supporté pour les sondes de date")
if probe_type == "elapsed_distance" and metric_unit != "km":
raise ValueError("seul probe.metric.unit=km est supporté pour elapsed_distance")
if probe_type == "remaining_quantity" and metric_unit not in {"%", "units", "litres"}:
raise ValueError("probe.metric.unit doit être %, units ou litres pour remaining_quantity")
thresholds = probe.get("thresholds")
if not isinstance(thresholds, dict):

View file

@ -645,6 +645,24 @@ def page_item(domain: str, item_key: str) -> HTMLResponse:
</form>
</section>
"""
elif allow_manual_edit and form_mode == "remaining_quantity":
unit = str(service.get("probe", {}).get("metric", {}).get("unit", "")).strip()
unit_hint = f" ({html_escape(unit)})" if unit else ""
manual_form_html = f"""
<section class="card">
<h2>Mettre à jour la quantité restante</h2>
<p class="muted">Saisir la quantité actuellement disponible{unit_hint}.</p>
<form method="post" action="/life-noc/item/{html_escape(domain)}/{html_escape(item_key)}/set" class="form-grid">
<label>Quantité restante{unit_hint}
<input type="text" inputmode="decimal" name="value" value="{html_escape(current_input.get('value', ''))}" required>
</label>
<input type="hidden" name="origin" value="manual">
<div class="actions">
<button type="submit">Enregistrer</button>
</div>
</form>
</section>
"""
complete_form_html = ""
if allow_complete: