Les boutons comptés
Sur une fiche client, on veut voir « 12 commandes » et cliquer dessus. Le problème n’est pas l’affichage : c’est que le module qui possède la fiche client ne doit rien savoir du module des ventes. Un import direct entre modules métier est interdit (règle n°8), et pour une bonne raison : le jour où le client désinstalle les ventes, la fiche client ne doit pas se casser.
Le module consommateur déclare le lien sur le modèle d’en face, et personne ne se connaît.
from kewos.smart_buttons import has_smart_button, register_smart_button
def register(registry): ... if not has_smart_button("kws_partner", "invoices"): # le boot réimporte register_smart_button( "kws_partner", # la fiche qui portera le bouton (module core) "invoices", # sa clé, unique sur ce modèle label_key="account.smartbutton.partner_moves", target_model="account_move", # ce qu'on compte (module account) filter_field="partner_id", # le champ qui pointe vers la fiche icon="receipt", )C’est le module account qui écrit ces lignes. core, qui possède kws_partner, ne mentionne
account nulle part. Retirez account, le bouton disparaît ; la fiche partenaire, elle, ne
bouge pas.
Ce que le serveur renvoie
Un seul point d’entrée générique, pour n’importe quel modèle :
GET /api/v1/library_title/1/smart-buttons
[{"key":"copies","label_key":"library.smartbutton.copies","icon":"book", "count":2,"target_model":"library_copy","filter_field":"title_id", "filter_value":1,"target_module":"library"}]Le décompte est réel (select count(*) from library_copy where title_id = 1 renvoie bien 2), et
le frontend n’a rien de spécifique à savoir : avec target_module, target_model,
filter_field et filter_value, il sait afficher le bouton et où mener au clic. Aucun écran
n’est codé en dur (règle n°48).
Le décompte n’est pas un count(*) naïf
Il tourne dans la session filtrée, avec les règles d’enregistrement et le droit de lecture de l’appelant. Deux conséquences qu’il faut avoir en tête :
- deux utilisateurs peuvent voir deux nombres différents sur la même fiche, et c’est correct : chacun compte ce qu’il a le droit de voir. Un commercial qui ne voit que ses commandes lit son propre total ;
- le nombre ne fuite pas ce que la liste cacherait. Un décompte global aurait révélé l’existence d’enregistrements invisibles, ce qui est une fuite d’information même sans en montrer le contenu.
La fiche elle-même est chargée par la session filtrée avant tout décompte : demander les boutons d’un enregistrement qu’on n’a pas le droit de lire répond 404, pas 403. Ne pas avoir le droit et ne pas exister se ressemblent, volontairement.
GET /api/v1/library_title/9999/smart-buttons -> 404Le champ groups
register_smart_button(..., groups=["accounting_auditor"])Il masque le bouton pour les autres. Ce n’est pas un contrôle de sécurité : c’est du rangement d’écran. La sécurité, c’est le décompte filtré et le 404 ci-dessus, qui tiennent même si quelqu’un appelle l’endpoint à la main.