# AdvancedStockAtDate — exploiter la page « Stock à date » (Dolibarr)

Module Dolibarr qui complète la page **Stock à date**. Aucun fichier du cœur n'est modifié :
tout passe par les hooks natifs du contexte `stockatdate`.

## Le problème

La page native répond à une question comptable — combien y avait-il en stock tel jour — et
s'arrête là. Il lui manque trois choses pour être utilisable au quotidien :

- **aucune valorisation au prix de revient**, alors que c'est le chiffre attendu en clôture ;
- **aucun total** : la page liste, sans jamais additionner ;
- **les produits à zéro qui n'ont jamais bougé sont listés comme les autres**. Sur un catalogue
  de plusieurs milliers de références, l'écran devient illisible et la pagination trompeuse.

## Ce que le module apporte

**Une colonne « Prix de revient »**, valorisée au stock de la date choisie — et non au stock du
jour, ce qui n'aurait pas de sens sur un écran daté.

**Quatre encarts de totaux** : valorisation PMP, prix de revient, valeur vente, stock actuel.

**Une case « Masquer les produits à 0 sans mouvement »**, cochable à la volée sur la page. Son
état de départ se règle dans la configuration du module.

## Deux choix d'implémentation qui méritent une explication

**Tout est calculé par la base de données.** Les totaux sont obtenus par une requête d'agrégat,
et la colonne par une expression corrélée. Rien n'est totalisé en PHP : la page peut lister des
milliers de produits, les charger pour les additionner serait intenable. L'expression de colonne
est corrélée plutôt que jointe, car une jointure supplémentaire fausserait les agrégats que la
requête native calcule déjà.

**Le masquage passe par `printFieldListGroupBy`, pas par `printFieldListWhere`.** C'est
contre-intuitif pour une clause `WHERE`, mais dans `product/stock/stockatdate.php` le hook
`printFieldListWhere` est consommé **après** l'ajout du `GROUP BY` : il est donc inutilisable ici.
Le `resPrint` de `printFieldListGroupBy` est au contraire ajouté au SQL **juste avant** le
`GROUP BY`. La condition arrive au bon endroit, et comme elle est dans le `WHERE`, le compteur
de pagination reste juste.

## Compatibilité

| Version | Colonne et totaux | Masquage des produits vides |
|---|---|---|
| **23.0+**, **24.0** | ✅ | ✅ |
| **18.0 → 22.0** | ✅ | ❌ |

Le masquage exige `printFieldListGroupBy`, apparu en **23.0**. Avant, aucun hook de la page ne
permet d'ajouter une clause `WHERE`. Le module le détecte en lisant la page une fois par requête —
plutôt qu'en comparant un numéro de version, ce qui reste vrai si le hook a été rétroporté — et
**n'affiche pas la case** quand elle serait sans effet : mieux vaut aucune case qu'une case qui
ne filtre rien.

PHP 7.0+.

## Installation

1. Copier le dossier dans `htdocs/custom/advancedstockatdate/`.
2. Activer le module dans *Configuration → Modules → Produits*.
3. Régler l'état par défaut du masquage dans sa page de configuration.

Aucune table n'est créée, et la désactivation conserve le réglage.

## Origine

Extrait du module `customops` (instance OPS, Dolibarr 23.0.3), où cette fonctionnalité avait été
écrite puis éprouvée. Le code y remplaçait déjà un patch cœur historique ; ce module le rend
réutilisable sur n'importe quelle instance.

## Licence

GPL v3 ou ultérieure.
