Anomalie dans la gestion Stock Virtuel

Bonjour,

J’utilise Dolibarr v13 et j’ai remarqué une anomalie dans la gestion des stocks qui est gênante.
j’ai bien validé la fonction :
Incrémenter les stocks physiques sur validation des réceptions.
Hors je constate que le stock réel s’incrémente bien , pas de problème.
C’est du coté stock virtuel que cela me gène et a mon avis n’est pas correcte.
Je m’explique :
il faut absolument faire une validation des produits 'reçu complément ’ pour mettre a jour le stock virtuel.
Si on fait une réception partielle ce qui arrive souvent , tous les items de la commande au complet reste
a attente de réception alors que certain ont été reçu … ce qui est faux.
exemple :
stock avant commande X : 0 et Y : 0
j’ai 10 items X et 5 items Y dans une commande fournisseur.
je réceptionne seulement les 10 items X , et classe la réception ’ partiellement reçu ’ ( ce qui est le cas )
je vais avoir 10 X en stock et stock virtuel 20 … ce qui est faux.
le Y reste a 0 en stock et 5 virtuel, c’est correcte.
Tant que la réception ne sera pas complète pour cette commande le stock virtuel sera faux.
J’espère avoir bien expliqué le problème.
On dirai que la configuration dans le module de stock :
Incrémenter les stocks physiques sur validation des réceptions, ne fonctionne pas correctement pour les réceptions partielles.
Bravo la communauté pour ce fantastique DOLIBARR. je suis fan.

Fabrice - Canada

Bonjour,

J’ai modifié la fonction load_stats_commande_fournisseur dans product/class/product.class.php comme suivant, et ça semble corriger le problème :

public function load_stats_commande_fournisseur($socid = 0, $filtrestatut = '', $forVirtualStock = 0)
	{
		// phpcs:enable
		global $conf, $user, $hookmanager, $action;

		$sql = "SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
		$sql .= " COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty, SUM(r.qty) AS qty_rec";
		$sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur c ON c.rowid = cd.fk_commande";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe s ON c.fk_soc = s.rowid";
		if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id;
		}
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur_dispatch r ON  r.fk_commandefourndet=cd.rowid ";
		$sql .= " WHERE c.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ? 'stock' : 'supplier_order').")";
		$sql .= " AND cd.fk_product = ".$this->id;

		if ($socid > 0) {
			$sql .= " AND c.fk_soc = ".((int) $socid);
		}
		if ($filtrestatut != '') {
			$sql .= " AND c.fk_statut in (".$this->db->sanitize($filtrestatut).")"; // Peut valoir 0
		}

		$result = $this->db->query($sql);
		if ($result) {
			$obj = $this->db->fetch_object($result);
			$this->stats_commande_fournisseur['suppliers'] = $obj->nb_suppliers;
			$this->stats_commande_fournisseur['nb'] = $obj->nb;
			$this->stats_commande_fournisseur['rows'] = $obj->nb_rows;
			$this->stats_commande_fournisseur['qty'] = $obj->qty ? $obj->qty : 0;
			
			$this->stats_commande_fournisseur['qty']-= $obj->qty_rec ? $obj->qty_rec : 0;

			$parameters = array('socid' => $socid, 'filtrestatut' => $filtrestatut, 'forVirtualStock' => $forVirtualStock);
			$reshook = $hookmanager->executeHooks('loadStatsSupplierOrder', $parameters, $this, $action);
			if ($reshook > 0) {
				$this->stats_commande_fournisseur = $hookmanager->resArray['stats_commande_fournisseur'];
			}

			return 1;
		} else {
			$this->error = $this->db->error().' sql='.$sql;
			return -1;
		}
	}

Bonjour @FabriceFleury

Je viens d’appliquer le code.
A priori ça resoud bien la première demande mais il y a un cas qui n’est pas traité:

Exemple:
Si j’ai commandé 100 pièces X et que je valide la réception de 40 pièces X.
Je devrais avoir 40 en stock physique et 60 en virtuel
Sauf que les 40 partent bien dans le stock réel mais ne sont pas décrémentés du stock virtuel qui reste à 100 alors que celui ci devrait etre à 60

Pas simple :slight_smile:

Je continu de chercher…

Bonjour Pat2475,

Je vois que ma demande n’est pas resté sans réaction, j’ai cru que personne ne me comprenait … LOL

Bravo et encore merci pour les efforts que vous mettez à corriger ce problème de gestion de stock dans Dolibarr.

Est-ce que vous pensez pouvoir y remédier ?

J’attends avec impatience votre solution.

Si vous avez besoin de plus d’informations n’hésitez pas à me contacter.

Merci de me tenir informé.

Bonne fin de journée.

1 « J'aime »

Si ton stock de départ est 0x
Si tu commandes 100x et que tu valides la réception de 40x
le stock réel doit être de 40 ( celle que tu as reçu ) , ce qui est correcte.
par contre le stock virtuel est bien de 100x et non de 60x.
60x est le stock que tu n’as pas encore reçu, donc le stock en attente de réception.
100x est bien stock que tu auras à la fin de toutes les réceptions, donc virtuellement tu en auras 100x à la fin.

Voila tel que que je le comprends.

Est-ce que cette correction va être intégrée au code final ?

Note : je dois la tester, je reviens de vacances et n’est pas eu le temps de faire le test.

Fabrice - Canada

Bonjour Fabrice,
On a un point de vu différent :slight_smile:
Le stock virtuel ce sont les x commandés mais pas encore reçu donc pas présent dans le stock réel.
Si ton stock est 0x et que tu commande 100x, le stock virtuel s’incrémente de 100x.
Tu valide la réception de 40x, le stock réel passe à 40 et le stock virtuel passe à 60 puisque 40x se sont déplacés du stock virtuel vers le stock réel. Il reste plus qu’à réceptionner 60x
Une fois les 60x réceptionnées le stock passe à 100 et le stock virtuel à zéro.
Le placement d’une nouvelle commande fournisseur de 50x augmentera le stock virtuel de 50x jusqu’à la réception partiel ou complète qui incrémentera alors le stock physique et décrémentera le stock virtuel.

Patrick - France

Bonjour @pat2475

C’est @FabriceFleury qui a bon ! Relisez l’info Dolibarr :wink:


@+

Bonjour,

Je confirme que la correction de ‹ aurelienL › corrige bien le bug de la gestion des stocks virtuel.
Très fort :slight_smile:
Est-ce que cela va être intégré au futur version ?
Je compte éventuellement passer a la dernière version 14 , d’où ma question.

Bravo la communauté pour ce fantastique DOLIBARR. je suis fan.

Fabrice - Canada

@philazerty

Je viens de vérifier et effectivement je n’avais pas bien compris le stock virtuel :slight_smile:
Du coup c’est tout bon !

Merci pour ce correctif !

Bonjour,

Je me suis rendu compte que pour des commandes fournisseurs réceptionnées en plusieurs fois et encore non réceptionnées complètement, il y avait toujours un problème.
Voici donc ma correction :

public function load_stats_commande_fournisseur($socid = 0, $filtrestatut = '', $forVirtualStock = 0)
	{
		// phpcs:enable
		global $conf, $user, $hookmanager, $action;

		$sql = "SELECT COUNT(DISTINCT c.fk_soc) as nb_suppliers, COUNT(DISTINCT c.rowid) as nb,";
		$sql .= " COUNT(cd.rowid) as nb_rows, SUM(cd.qty) as qty, SUM(r.qty_rec) AS qty_rec";
		$sql .= " FROM ".MAIN_DB_PREFIX."commande_fournisseurdet as cd";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."commande_fournisseur c ON c.rowid = cd.fk_commande";
		$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe s ON c.fk_soc = s.rowid";
		if (empty($user->rights->societe->client->voir) && !$socid && !$forVirtualStock) {
			$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON c.fk_soc = sc.fk_soc AND sc.fk_user = ".$user->id;
		}
		$sql .= " LEFT JOIN (select SUM(qty) as qty_rec, fk_commandefourndet as row_recep FROM llx_commande_fournisseur_dispatch GROUP BY fk_commandefourndet) r ON r.row_recep=cd.rowid ";
		$sql .= " WHERE c.entity IN (".getEntity($forVirtualStock && !empty($conf->global->STOCK_CALCULATE_VIRTUAL_STOCK_TRANSVERSE_MODE) ? 'stock' : 'supplier_order').")";
		$sql .= " AND cd.fk_product = ".$this->id;

		if ($socid > 0) {
			$sql .= " AND c.fk_soc = ".((int) $socid);
		}
		if ($filtrestatut != '') {
			$sql .= " AND c.fk_statut in (".$this->db->sanitize($filtrestatut).")"; // Peut valoir 0
		}
		

		$result = $this->db->query($sql);
		if ($result) {
			$obj = $this->db->fetch_object($result);
			$this->stats_commande_fournisseur['suppliers'] = $obj->nb_suppliers;
			$this->stats_commande_fournisseur['nb'] = $obj->nb;
			$this->stats_commande_fournisseur['rows'] = $obj->nb_rows;
			$this->stats_commande_fournisseur['qty'] = $obj->qty ? $obj->qty : 0;
			
			$this->stats_commande_fournisseur['qty']-= $obj->qty_rec ? $obj->qty_rec : 0;

			$parameters = array('socid' => $socid, 'filtrestatut' => $filtrestatut, 'forVirtualStock' => $forVirtualStock);
			$reshook = $hookmanager->executeHooks('loadStatsSupplierOrder', $parameters, $this, $action);
			if ($reshook > 0) {
				$this->stats_commande_fournisseur = $hookmanager->resArray['stats_commande_fournisseur'];
			}

			return 1;
		} else {
			$this->error = $this->db->error().' sql='.$sql;
			return -1;
		}
	}

Bonjour @aurelienL et merci
Pouvez-vous plutôt proposer votre correctif sur github ? Ici il a peu de chance d’être intégré.
Pensez à préciser la version et le fichier corrigé :wink:
Merci beaucoup
@+